@IT·互联网

C#.NET 主机详解

2025-07-31  本文已影响0人  青枫教学

简介

C#.NET 中,主机 (Host) 是一个用于封装应用程序资源和生命周期管理的组件。它提供了一种统一的方式来配置、启动和停止应用程序,是构建现代 .NET 应用的基础架构。

普通主机 (HostBuilder)

普通主机是 .NET Core 2.1 引入的基础主机模型,主要用于非 Web 应用场景。它提供了以下核心功能:

普通主机的基本示例:

using Microsoft.Extensions.Hosting;

var host = Host.CreateDefaultBuilder(args)
    .ConfigureServices((hostContext, services) =>
    {
        // 注册服务
        services.AddTransient<IMyService, MyService>();
    })
    .Build();

// 启动主机
await host.StartAsync();

// 应用逻辑...

// 停止主机
await host.StopAsync();

通用主机 (Generic Host)

通用主机是普通主机的增强版本,从 .NET Core 3.0 开始引入,专为构建非 HTTP 应用 (如控制台应用、Worker 服务、后台任务等) 而设计。

核心特性

通用主机创建 Worker 服务的示例:

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;

    public Worker(ILogger<Worker> logger)
    {
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
            await Task.Delay(1000, stoppingToken);
        }
    }
}

// 主机配置
var host = Host.CreateDefaultBuilder(args)
    .ConfigureServices((hostContext, services) =>
    {
        // 添加Worker服务
        services.AddHostedService<Worker>();
    })
    .ConfigureLogging(logging =>
    {
        logging.AddConsole();
    })
    .Build();

await host.RunAsync();
核心组件
优点
创建通用主机

通用主机通过 Host.CreateDefaultBuilder() 创建,它会自动配置一些默认行为(如日志、配置、依赖注入)。

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        // 创建主机
        using var host = Host.CreateDefaultBuilder(args)
            .ConfigureServices((context, services) =>
            {
                // 注册服务
                services.AddHostedService<MyHostedService>();
            })
            .Build();

        // 启动主机
        await host.RunAsync();
    }
}
配置主机

Host.CreateDefaultBuilder() 提供默认配置,包括:

可以通过 HostBuilder 自定义配置:

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        using var host = Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((context, config) =>
            {
                // 添加额外的配置源
                config.AddJsonFile("customsettings.json", optional: true);
            })
            .ConfigureServices((context, services) =>
            {
                // 注册自定义服务
                services.AddSingleton<IMyService, MyService>();
                services.AddHostedService<MyHostedService>();
            })
            .ConfigureLogging(logging =>
            {
                // 配置日志
                logging.AddConsole();
            })
            .Build();

        await host.RunAsync();
    }
}
实现 IHostedService

IHostedService 是通用主机中用于定义后台服务的接口,适合长时间运行的任务(如定时任务、消息队列处理)。它包含两个主要方法:

using Microsoft.Extensions.Hosting;
using System.Threading;
using System.Threading.Tasks;

public class MyHostedService : IHostedService
{
    public Task StartAsync(CancellationToken cancellationToken)
    {
        // 启动逻辑
        Console.WriteLine("MyHostedService is starting...");
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        // 关闭逻辑
        Console.WriteLine("MyHostedService is stopping...");
        return Task.CompletedTask;
    }
}
使用 BackgroundService

BackgroundServiceIHostedService 的一个抽象基类,简化了后台任务的实现。它适合需要循环运行的任务(如定时任务)。

using Microsoft.Extensions.Hosting;
using System;
using System.Threading;
using System.Threading.Tasks;

public class TimedHostedService : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            Console.WriteLine($"TimedHostedService is running at {DateTime.Now}");
            await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
        }
    }
}

注册服务:

services.AddHostedService<TimedHostedService>();
依赖注入

通用主机内置了依赖注入容器,可以注册服务并在应用程序中使用:

public interface IMyService
{
    void DoWork();
}

public class MyService : IMyService
{
    public void DoWork() => Console.WriteLine("MyService is working!");
}

public class MyHostedService : BackgroundService
{
    private readonly IMyService _myService;

    public MyHostedService(IMyService myService)
    {
        _myService = myService;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            _myService.DoWork();
            await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
        }
    }
}

注册服务:

services.AddSingleton<IMyService, MyService>();
services.AddHostedService<MyHostedService>();
通用主机的典型应用场景

主机生命周期管理

主机提供了完整的生命周期管理,主要通过以下接口实现:

IHostedService 接口

public interface IHostedService
{
    Task StartAsync(CancellationToken cancellationToken);
    Task StopAsync(CancellationToken cancellationToken);
}

生命周期事件

主机提供了三个主要的生命周期事件:

var host = Host.CreateDefaultBuilder(args)
    .Build();

var applicationLifetime = host.Services.GetRequiredService<IApplicationLifetime>();

applicationLifetime.ApplicationStarted.Register(() =>
{
    Console.WriteLine("应用已启动");
});

applicationLifetime.ApplicationStopping.Register(() =>
{
    Console.WriteLine("应用正在停止...");
});

applicationLifetime.ApplicationStopped.Register(() =>
{
    Console.WriteLine("应用已停止");
});

await host.RunAsync();

配置与依赖注入

var host = Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((hostingContext, config) =>
    {
        // 添加JSON配置文件
        config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
        
        // 添加环境变量配置
        config.AddEnvironmentVariables();
        
        // 添加命令行参数配置
        config.AddCommandLine(args);
    })
    .Build();

// 获取配置
var configuration = host.Services.GetRequiredService<IConfiguration>();
var value = configuration["MySetting"];
var host = Host.CreateDefaultBuilder(args)
    .ConfigureServices((hostContext, services) =>
    {
        // 注册单例服务
        services.AddSingleton<IMySingletonService, MySingletonService>();
        
        // 注册作用域服务
        services.AddScoped<IMyScopedService, MyScopedService>();
        
        // 注册瞬态服务
        services.AddTransient<IMyTransientService, MyTransientService>();
        
        // 注册主机服务
        services.AddHostedService<MyBackgroundService>();
    })
    .Build();

背景与演进

ASP.NET Core 1.x–2.x 的 Web 主机

.NET Core 3.0+ 的通用主机(Generic Host)

主机类型对比

特性/接口 Web Host (IWebHostBuilder) Generic Host (IHostBuilder)
适用场景 仅限 ASP.NET Core Web 应用 控制台、后台 Worker、Web 及混合场景
核心接口 IWebHostBuilderIWebHost IHostBuilderIHost
默认组件 Kestrel、IIS 集成、中间件管道 DI、配置(JSON/Env/Args)、日志、HostedService
Startup 支持 Startup 类 => ConfigureServicesConfigure Startup,服务配置与管道在 Program.cs 中完成
扩展灵活度 对 Web 优化,扩展槽较少 核心抽象化,扩展性极强

核心概念与关键接口

IHostBuilder & Host

通用主机(Generic Host)常用扩展包

IHostedService 与 BackgroundService

public class TimedWorker : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            // 周期性执行
            await DoWorkAsync();
            await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
        }
    }
}

配置与启动流程解析

Program.cs(.NET 6+ 最简模板)

var builder = Host.CreateDefaultBuilder(args)
    .ConfigureServices((hostCtx, services) =>
    {
        services.AddHostedService<TimedWorker>();
        // 其它服务注册
    })
    .ConfigureLogging(logging =>
    {
        logging.ClearProviders();
        logging.AddConsole();
    });

var host = builder.Build();
await host.RunAsync();

配置加载顺序

依赖注入生命周期

日志管道

主机构建流程

最小主机WebApplication

概念背景

基本概念

WebApplication 是一个集成了主机配置、服务注册和请求处理管道的单一类型,它结合了早期版本中的 HostBuilder、WebHostBuilderStartup 类的功能。

核心特点包括:

核心类型

类型 作用
WebApplicationBuilder 构建器,负责加载配置、DI 注册、日志及 Kestrel 默认设置
WebApplication 真正的应用主机,承载中间件管道、路由和运行生命周期
IEndpointRouteBuilder 定义路由与端点,支持最小 API 风格

典型 Program.cs 模板

var builder = WebApplication.CreateBuilder(args);

// 1. 服务注册(依赖注入)
builder.Services.AddControllers();
builder.Services.AddDbContext<AppDbContext>(opt =>
    opt.UseSqlServer(builder.Configuration.GetConnectionString("Default")));

// 2. 构建应用
var app = builder.Build();

// 3. 中间件配置
if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();

// 4. 路由与端点
app.MapControllers();
app.MapGet("/ping", () => Results.Ok("pong"));

// 5. 启动
app.Run();

依赖注入与配置

var builder = WebApplication.CreateBuilder(args);

// 添加控制器支持
builder.Services.AddControllers();

// 添加 Swagger/OpenAPI 支持
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// 添加自定义服务
builder.Services.AddScoped<IMyService, MyService>();

var app = builder.Build();
var builder = WebApplication.CreateBuilder(args);

// 读取配置值
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");

// 绑定配置到强类型对象
var settings = builder.Configuration.GetSection("AppSettings").Get<AppSettings>();

// 添加配置源
builder.Configuration.AddJsonFile("appsettings.Development.json", optional: true);

中间件与管道

// 配置中间件
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();

// 映射控制器
app.MapControllers();

// 或使用最小 API
app.MapGet("/greet/{name}", (string name) => $"Hello, {name}!");

最小 API(Minimal API)

// 定义路由和处理逻辑
app.MapGet("/users", () =>
{
    var users = new[] { 
        new { Id = 1, Name = "Alice" },
        new { Id = 2, Name = "Bob" } 
    };
    return Results.Ok(users);
});

app.MapPost("/users", (User user) =>
{
    // 处理用户创建逻辑
    return Results.Created($"/users/{user.Id}", user);
});

// 带参数的路由
app.MapGet("/users/{id}", (int id) =>
{
    // 查找用户逻辑
    var user = GetUserById(id);
    return user is not null ? Results.Ok(user) : Results.NotFound();
});

依赖注入与服务使用

app.MapGet("/todos", async (ITodoService todoService) =>
    await todoService.GetAllTodos());

app.MapGet("/todos/{id}", async (int id, ITodoService todoService) =>
    await todoService.GetTodoById(id)
        is Todo todo
            ? Results.Ok(todo)
            : Results.NotFound());

环境感知

通过 app.Environment 可以获取当前环境信息:

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

启动与生命周期

高级特性

可以为路由添加全局或特定的过滤器:

// 全局过滤器
app.MapGet("/", () => "Hello World!")
   .AddEndpointFilter(async (context, next) =>
   {
       Console.WriteLine("Before endpoint execution");
       var result = await next(context);
       Console.WriteLine("After endpoint execution");
       return result;
   });

组织相关路由到组中:

var usersGroup = app.MapGroup("/users");

usersGroup.MapGet("/", GetAllUsers);
usersGroup.MapGet("/{id}", GetUserById);
usersGroup.MapPost("/", CreateUser);
app.MapPost("/products", (ProductRequest request) =>
{
    if (!ModelState.IsValid)
    {
        return Results.ValidationProblem(ModelState);
    }
    
    // 处理有效请求
    return Results.Created($"/products/{request.Id}", request);
});

public class ProductRequest
{
    public int Id { get; set; }
    
    [Required]
    public string Name { get; set; }
    
    [Range(0, 100)]
    public decimal Price { get; set; }
}
app.Use(async (context, next) =>
{
    // 请求前处理
    var start = DateTime.UtcNow;
    
    await next.Invoke();
    
    // 请求后处理
    var duration = DateTime.UtcNow - start;
    logger.LogInformation($"Request took {duration.TotalMilliseconds}ms");
});
   app.UseExceptionHandler(exceptionHandlerApp => 
   {
       exceptionHandlerApp.Run(async context => 
       {
           context.Response.StatusCode = 500;
           await context.Response.WriteAsJsonAsync(new { 
               Error = "An unexpected error occurred" 
           });
       });
   });

与传统 Startup/Host 对比

特性 传统模式(.NET 5 及以前) 最小主机(.NET 6+)
样板代码 Host.CreateDefaultBuilder + Startup WebApplication.CreateBuilder
服务注册分散 ConfigureServices in Startup 统一在 builder.Services
中间件配置 Configure in Startup 直接在 app 上链式调用
路由定义 控制器 + MapControllers() 最小 API + 控制器混合
可读性 分文件稍散 单文件、扁平化,更易快速浏览

实战示例:带 Swagger 的最小 API

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.MapGet("/hello/{name}", (string name) => $"Hello, {name}!")
   .WithName("SayHello")
   .WithOpenApi();

app.Run();

最佳实践

上一篇 下一篇

猜你喜欢

热点阅读