.NET 6 Startup.csの廃止とDbContextの追加方法
問題の概要
.NET 5から.NET 6にアップグレードした際、Startup.cs
クラスが存在しないことに気づく開発者が多くいます。これまでStartup.cs
で行っていた依存関係の登録(DIコンテナの設定)やミドルウェアの構成、特にDbContextの設定方法がわからなくなるという問題が発生します。
INFO
.NET 6では、ASP.NET Coreのテンプレートが簡素化され、Program.cs
とStartup.cs
が統合されました。これは「Minimal API」アプローチの一部として導入された変更です。
基本的な解決方法
従来の方法(.NET 5以前)
// Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
}
.NET 6での新しい方法
// Program.cs
var builder = WebApplication.CreateBuilder(args);
// サービス登録(従来のConfigureServicesに相当)
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
var app = builder.Build();
// ミドルウェア設定(従来のConfigureに相当)
// ...
app.Run();
実践的なコード例
以下は、実際のプロジェクトで使用できる完全なProgram.csの例です:
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
// サービス登録セクション
builder.Services.AddControllers().AddNewtonsoftJson();
// DbContextの登録
builder.Services.AddDbContext<BookStoreContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("BookStoreDB")));
// Identity設定
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"]))
};
});
// Swagger/OpenAPI
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// カスタムサービスの登録
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();
拡張メソッドを使用した整理方法
大規模なプロジェクトでは、Program.csが複雑になるのを防ぐために拡張メソッドを使用する方法があります:
public static class HostingExtensions
{
public static WebApplication ConfigureServices(this WebApplicationBuilder builder)
{
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// DbContextの登録
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
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;
}
}
var builder = WebApplication.CreateBuilder(args);
builder.ConfigureServices().ConfigurePipeline().Run();
従来のStartupクラスを維持する方法
どうしても従来のStartupクラスパターンを維持したい場合は、以下のようにカスタムStartupクラスを作成できます:
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")));
}
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();
よくあるサービスの登録方法
// 毎回新しいインスタンスが生成されます
builder.Services.AddTransient<IEmailService, EmailService>();
// 同一HTTPリクエスト内で同じインスタンスが使用されます
builder.Services.AddScoped<IUserRepository, UserRepository>();
// アプリケーション全体で一つのインスタンスが共有されます
builder.Services.AddSingleton<ICacheService, CacheService>();
まとめ
.NET 6ではStartup.cs
が廃止され、すべての設定がProgram.cs
に統合されました。これにより:
- コードの簡素化: 2つのファイルを行き来する必要がなくなりました
- 可読性の向上: 設定が一箇所に集約されました
- 柔軟性: 必要に応じて従来のパターンも維持できます
DbContextの追加はbuilder.Services.AddDbContext<>()
を使用し、接続文字列はbuilder.Configuration.GetConnectionString()
で取得します。大規模なプロジェクトでは拡張メソッドやカスタムStartupクラスを使用して整理することをおすすめします。
TIP
.NET 6以降でも、従来のStartupクラスパターンを使用することは可能ですが、Microsoftが推奨する新しいMinimal APIパターンに適応することが長期的なメンテナンス性を高めます。