Skip to content

.NET 6 中配置数据库上下文和服务的完整指南

.NET 6 引入了重大的架构变化,将传统的 Startup.csProgram.cs 文件合并为一个简化的 Program.cs 文件。本文将详细介绍如何在这一变化中配置数据库上下文和各种服务。

重要变化

从 .NET 6 开始,Microsoft 移除了单独的 Startup.cs 类,所有配置现在都在 Program.cs 中完成

基本的 Program.cs 配置

csharp
var builder = WebApplication.CreateBuilder(args);

// 添加数据库上下文
builder.Services.AddDbContext<ApplicationDbContext>(options => 
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

var app = builder.Build();
// 中间件配置...
app.Run();

完整的配置示例

以下是一个完整的 Program.cs 配置示例,包含了数据库上下文、身份认证、Swagger 等常见配置:

csharp
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

// 数据库上下文配置
builder.Services.AddDbContext<BookStoreContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("BookStoreDB")));

// 控制器和 API 配置
builder.Services.AddControllers().AddNewtonsoftJson();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// 身份认证配置
builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<BookStoreContext>()
    .AddDefaultTokenProviders();

// JWT 配置
builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(option =>
{
    option.SaveToken = true;
    option.RequireHttpsMetadata = false;
    option.TokenValidationParameters = new TokenValidationParameters()
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidAudience = builder.Configuration["JWT:ValidAudience"],
        ValidIssuer = builder.Configuration["JWT:ValidIssuer"],
        IssuerSigningKey = new SymmetricSecurityKey(
            Encoding.UTF8.GetBytes(builder.Configuration["JWT:Secret"]))
    };
});

// 自定义服务注册
builder.Services.AddTransient<IBookRepository, BookRepository>();
builder.Services.AddTransient<IAccountRepository, AccountRepository>();

// CORS 配置
builder.Services.AddCors(option =>
{
    option.AddDefaultPolicy(builder =>
    {
        builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
    });
});

var app = builder.Build();

// 开发环境配置
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();

app.Run();

扩展方法模式(推荐)

为了保持代码的整洁和可维护性,推荐使用扩展方法模式:

csharp
// HostingExtensions.cs
public static class HostingExtensions
{
    public static WebApplication ConfigureServices(this WebApplicationBuilder builder)
    {
        // 服务配置
        builder.Services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
        
        builder.Services.AddControllers();
        builder.Services.AddEndpointsApiExplorer();
        builder.Services.AddSwaggerGen();
        
        return builder.Build();
    }

    public static WebApplication ConfigurePipeline(this WebApplication app)
    {
        if (app.Environment.IsDevelopment())
        {
            app.UseSwagger();
            app.UseSwaggerUI();
        }

        app.UseHttpsRedirection();
        app.UseAuthorization();
        app.MapControllers();
        
        return app;
    }
}

// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.ConfigureServices().ConfigurePipeline().Run();

传统的 Startup 类方式

如果你更喜欢传统的 Startup.cs 模式,也可以手动重新创建:

csharp
// Startup.cs
public class Startup
{
    public IConfiguration Configuration { get; }
    
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
        
        services.AddControllersWithViews();
    }

    public void Configure(WebApplication app, IWebHostEnvironment env)
    {
        if (!env.IsDevelopment())
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseRouting();
        app.UseAuthorization();
        
        app.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    }
}

// Program.cs
var builder = WebApplication.CreateBuilder(args);
var startup = new Startup(builder.Configuration);

startup.ConfigureServices(builder.Services);
var app = builder.Build();
startup.Configure(app, app.Environment);

app.Run();

注意事项

  • 确保 appsettings.json 中包含正确的连接字符串配置
  • 数据库上下文的命名空间需要正确导入
  • 中间件的顺序很重要(如 UseRouting 必须在 UseAuthorization 之前)

服务注册的不同方式

在 .NET 6 中,服务的注册方式与之前类似,只是位置发生了变化:

csharp
// 瞬态服务(每次请求都创建新实例)
builder.Services.AddTransient<IEmailService, EmailService>();

// 作用域服务(每个请求一个实例)
builder.Services.AddScoped<IUserService, UserService>();

// 单例服务(整个应用生命周期一个实例)
builder.Services.AddSingleton<ICacheService, CacheService>();

总结

.NET 6 的简化编程模型使得应用程序配置更加简洁明了。虽然失去了传统的 Startup.cs 分离结构,但获得了更紧凑的代码布局。你可以根据项目需求选择直接在 Program.cs 中配置,使用扩展方法保持代码整洁,或者重新创建传统的 Startup 类结构。

迁移提示

从 .NET 5 迁移到 .NET 6 时,只需将 Startup.cs 中的内容移动到 Program.cs,并将 services 替换为 builder.Services 即可完成大部分迁移工作。