2.2 主机 (Host) 与服务 (Services) 2.2 主机 (Host) 与服务 (Services) 在 ASP.NET Core 中,主机 (Host) 和服务 (Services) 是应用程序启动和运行的核心构建块。它们共同负责应用程序的配置、依赖项注入、生命周期管理以及提供各种基础设施服务。理解它们的工作原理对于构建健壮且可维护的 ASP.NET Core 应用程序至关重要。 2.2.1 主机 (Host) 主机是 ASP.NET Core 应用程序的容器,负责启动和管理应用程序的整个生命周期。它封装了底层的服务器实现(例如 Kestrel),并提供了配置、日志记录和依赖项注入等关键服务。
在 ASP.NET Core 中,主机 (Host) 和服务 (Services) 是应用程序启动和运行的核心构建块。它们共同负责应用程序的配置、依赖项注入、生命周期管理以及提供各种基础设施服务。理解它们的工作原理对于构建健壮且可维护的 ASP.NET Core 应用程序至关重要。
主机是 ASP.NET Core 应用程序的容器,负责启动和管理应用程序的整个生命周期。它封装了底层的服务器实现(例如 Kestrel),并提供了配置、日志记录和依赖项注入等关键服务。
主机的主要职责:
引导应用程序: 主机负责启动应用程序,加载配置,并设置依赖项注入容器。
生命周期管理: 主机控制应用程序的启动、停止和销毁。
服务器绑定: 主机绑定到特定的服务器实现(例如 Kestrel),并监听传入的 HTTP 请求。
配置: 主机加载并管理应用程序的配置信息,例如连接字符串、应用程序设置等。
日志记录: 主机提供日志记录机制,用于记录应用程序的事件和错误。
依赖项注入: 主机配置和管理依赖项注入容器,用于解析和提供应用程序所需的依赖项。
创建主机:
在 ASP.NET Core 中,通常使用 WebHost.CreateDefaultBuilder 或 Host.CreateDefaultBuilder 方法来创建主机。 WebHost.CreateDefaultBuilder 主要用于 Web 应用程序,而 Host.CreateDefaultBuilder 用于非 Web 应用程序(例如控制台应用程序或后台服务)。
// 使用 WebHost 创建 Web 应用程序主机 public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); // 使用 Host 创建非 Web 应用程序主机 public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureServices((hostContext, services) => { services.AddHostedService<Worker>(); });
CreateDefaultBuilder 方法会自动配置以下内容:
配置: 从 appsettings.json、appsettings.{Environment}.json 文件加载配置,并添加环境变量和命令行参数作为配置源。
日志记录: 配置控制台和调试日志记录。
依赖项注入: 配置基本的依赖项注入容器。
Kestrel 服务器: 对于 Web 应用程序,配置 Kestrel 作为默认的 Web 服务器。
配置主机:
可以使用 ConfigureAppConfiguration、ConfigureLogging 和 ConfigureServices 方法来自定义主机。
ConfigureAppConfiguration: 用于添加或修改配置源。
ConfigureLogging: 用于配置日志记录提供程序和日志级别。
ConfigureServices: 用于注册应用程序的服务到依赖项注入容器中。
代码示例:
using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration((hostingContext, config) => { // 添加自定义配置源 config.AddJsonFile("myconfig.json", optional: true, reloadOnChange: true); }) .ConfigureLogging((hostingContext, logging) => { // 添加自定义日志记录提供程序 logging.AddConsole(); logging.AddDebug(); }) .ConfigureServices((hostContext, services) => { // 注册应用程序的服务 services.AddSingleton<IMyService, MyService>(); services.AddHostedService<MyBackgroundService>(); }); } public interface IMyService { string GetMessage(); } public class MyService : IMyService { public string GetMessage() { return "Hello from MyService!"; } } public class MyBackgroundService : BackgroundService { private readonly ILogger<MyBackgroundService> _logger; private readonly IMyService _myService; public MyBackgroundService(ILogger<MyBackgroundService> logger, IMyService myService) { _logger = logger; _myService = myService; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { _logger.LogInformation("Worker running at: {time} - {_message}", DateTimeOffset.Now, _myService.GetMessage()); await Task.Delay(1000, stoppingToken); } } }
流程图:
服务是指应用程序中可重用的组件,它们执行特定的任务或提供特定的功能。在 ASP.NET Core 中,服务通过依赖项注入容器进行注册和解析。
服务的主要职责:
提供可重用的功能: 服务封装了应用程序中常用的逻辑,例如数据访问、业务规则、身份验证等。
实现关注点分离: 服务将应用程序分解为更小的、更易于管理的部分,从而提高代码的可读性和可维护性。
支持测试: 服务可以通过接口进行定义,从而可以轻松地进行单元测试。
促进代码重用: 服务可以在应用程序的不同部分被重用,从而减少代码重复。
注册服务:
可以使用 ConfigureServices 方法将服务注册到依赖项注入容器中。 ASP.NET Core 提供了多种注册服务的方法:
AddTransient: 每次请求服务时,都会创建一个新的服务实例。
AddScoped: 在每个请求范围内,创建一个新的服务实例。对于 Web 应用程序,这意味着每个 HTTP 请求都会创建一个新的实例。
AddSingleton: 创建一个单例服务实例,并在应用程序的整个生命周期内共享该实例。
代码示例:
using Microsoft.Extensions.DependencyInjection; public class Startup { public void ConfigureServices(IServiceCollection services) { // 注册服务 services.AddTransient<ITransientService, TransientService>(); services.AddScoped<IScopedService, ScopedService>(); services.AddSingleton<ISingletonService, SingletonService>(); // 其他服务注册 services.AddControllers(); } // 其他配置 } public interface ITransientService { Guid GetGuid(); } public interface IScopedService { Guid GetGuid(); } public interface ISingletonService { Guid GetGuid(); } public class TransientService : ITransientService { private Guid _guid; public TransientService() { _guid = Guid.NewGuid(); } public Guid GetGuid() => _guid; } public class ScopedService : IScopedService { private Guid _guid; public ScopedService() { _guid = Guid.NewGuid(); } public Guid GetGuid() => _guid; } public class SingletonService : ISingletonService { private Guid _guid; public SingletonService() { _guid = Guid.NewGuid(); } public Guid GetGuid() => _guid; }
在这个例子中,ITransientService、IScopedService 和 ISingletonService 接口分别对应于瞬态、范围和单例服务。 ConfigureServices 方法使用 AddTransient、AddScoped 和 AddSingleton 方法将这些服务注册到依赖项注入容器中。
解析服务:
可以通过构造函数注入、属性注入或方法注入来解析服务。
构造函数注入: 将服务作为构造函数参数传递给类。
属性注入: 使用 [FromServices] 属性将服务注入到类的属性中。
方法注入: 将服务作为方法参数传递给方法。
代码示例:
using Microsoft.AspNetCore.Mvc; [ApiController] [Route("[controller]")] public class MyController : ControllerBase { private readonly IMyService _myService; // 构造函数注入 public MyController(IMyService myService) { _myService = myService; } [HttpGet] public string Get() { return _myService.GetMessage(); } }
在这个例子中,MyController 类通过构造函数注入获取 IMyService 接口的实例。
服务生命周期:
理解服务的生命周期对于避免资源泄漏和确保应用程序的正确行为至关重要。
瞬态服务: 每次请求服务时都会创建一个新的实例。 这适用于轻量级、无状态的服务。
范围服务: 在每个请求范围内创建一个新的实例。 对于 Web 应用程序,这意味着每个 HTTP 请求都会创建一个新的实例。 这适用于需要在请求范围内共享状态的服务。
单例服务: 在应用程序的整个生命周期内只创建一个实例。 这适用于重量级、共享状态的服务,例如缓存或数据库连接池。
选择正确的生命周期:
选择正确的服务生命周期取决于服务的具体需求。
如果服务是轻量级的、无状态的,并且不需要在请求之间共享状态,则应使用瞬态生命周期。
如果服务需要在请求范围内共享状态,则应使用范围生命周期。
如果服务是重量级的、共享状态的,并且需要在应用程序的整个生命周期内共享状态,则应使用单例生命周期。
总结:
主机和服务是 ASP.NET Core 应用程序的关键构建块。主机负责启动和管理应用程序的生命周期,而服务则提供可重用的功能。理解它们的工作原理对于构建健壮且可维护的 ASP.NET Core 应用程序至关重要。通过合理配置主机和服务,可以构建灵活、可扩展且易于测试的应用程序。