- WebApplication and WebApplicationBuilder
- Behavior differences in the hosting model
- Building libraries for ASP.NET Core
- FAQ
- Cheatsheet
.NET 6 introduces a new hosting model for ASP.NET Core applications. This model is streamlined and reduces the amount of boilerplate code required to get a basic ASP.NET Core application up and running.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World");
app.Run();This model unifies Startup.cs and Program.cs into a single file experience that takes advantage of top level statements to remove any boilerplate. There should be a mostly mechanial translation from .NET 5 projects using a Startup class to the new hosting model:
Program.cs (.NET 5)
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}Startup.cs (.NET 5)
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
}Program.cs (.NET 6)
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
app.Run();The above shows that ConfigureServices(IServiceCollection) can be configured using WebApplicationBuilder.Services and Configure(IApplicationBuilder...) can be configured by using WebApplication.
- The developer exception page middleware is enabled when the environment is
Development. - The endpoint routing middleware wraps the entire middleware pipeline. This means there's no need to have explicit calls to
UseEndpointsto register routes.UseRoutingcan still be used to move where route matching happens. - The final pipeline is created before any
IStartupFilterruns. This means that exceptions caused while building the main pipeline won't be visible to theIStartupFiltercall chain.
The existing .NET ecosystem has built extensibility around IServiceCollection, IHostBuilder and IWebHostBuilder. These properties are exposed on the WebApplicationBuilder as Services, Host and WebHost.
The WebApplication implements both Microsoft.AspNetCore.Builder.IApplicationBuilder and Microsoft.AspNetCore.Routing.IEndpointRouteBuilder.
We expect library authors to continue targeting IHostBuilder, IWebHostBuilder, IApplicationBuilder and IEndpointRouteBuilder when building ASP.NET Core specific components. This will ensure that your middleware, route handler, or other extensibility points continue to work across different hosting models.
Is the new hosting model less capable
No, it should be functionally equivalent for 98% to what you can do with the IHostBuilder and the IWebHostBuilder. There are
more advanced scenarios (the 2%) that will require specific knobs on IHostBuilder but we expect those to be extremely rare.
Is the generic hosting model dead?
No, it's not. It's an alternative model that will keep working forever. The generic host still underpins the new hosting model and is still the primary way to host worker based applications.
Do I have to migrate to the new hosting model
No, you don't have to. It's the preferred way to host ASP.NET Core applications from .NET 6 and onwards but you aren't forced to change your project layout if you have built up features around the Startup class.
Does WebApplicationFactory/TestServer still work?
WebApplicationFactory<TEntryPoint> is the way to test the new hosting model with the test server.
What if I was using a custom DI container?
That still works, here's an example that uses Autofac
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
// Register your own things directly with Autofac here. Don't
// call builder.Populate(), that happens in AutofacServiceProviderFactory
// for you.
builder.Host.ConfigureContainer<ContainerBuilder>(builder => builder.RegisterModule(new MyApplicationModule()));
var app = builder.Build();I like the Startup class, can I keep it?
Yes you can. Here's a shim you can use to keep it working as is:
Program.cs
var builder = WebApplication.CreateBuilder(args);
var startup = new Startup(builder.Configuration);
startup.ConfigureServices(builder.Services);
// Uncomment if using a custom DI container
// builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
// builder.Host.ConfigureContainer<ContainerBuilder>(startup.ConfigureContainer);
var app = builder.Build();
startup.Configure(app, app.Environment);
app.Run();Startup.cs
class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
}
// Uncomment if using a custom DI container
// public void ConfigureContainer(ContainerBuilder builder)
// {
// }
public void Configure(IApplicationBuilder app, IWebHostEnvironment environment)
{
}
}There are a few differences here:
- No more reflection magic to call the Startup class. You control the instantiation and lifetime.
- Any additional services injected into the Configure method need to be manually resolved by your
Program.cs.
.NET 5
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseEnvironment(Environments.Staging)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>()
.UseSetting(WebHostDefaults.ApplicationKey, typeof(Program).Assembly.FullName);
});.NET 6
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
ApplicationName = typeof(Program).Assembly.FullName,
ContentRootPath = Directory.GetCurrentDirectory(),
EnvironmentName = Environments.Staging
});
Console.WriteLine($"Application Name: {builder.Environment.ApplicationName}");
Console.WriteLine($"Environment Name: {builder.Environment.EnvironmentName}");
Console.WriteLine($"ContentRoot Path: {builder.Environment.ContentRootPath}");
var app = builder.Build();.NET 5
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(config =>
{
config.AddIniFile("appsettings.ini");
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});.NET 6
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddIniFile("appsettings.ini");
var app = builder.Build();.NET 5
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
logging.AddJsonConsole();
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});.NET 6
var builder = WebApplication.CreateBuilder(args);
// Configure JSON logging to the console
builder.Logging.AddJsonConsole();
var app = builder.Build();.NET 5
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Add the memory cache services
builder.Services.AddMemoryCache();
// Add a custom scoped service
builder.Services.AddScoped<ITodoRepository, TodoRepository>();
}
}.NET 6
var builder = WebApplication.CreateBuilder(args);
// Add the memory cache services
builder.Services.AddMemoryCache();
// Add a custom scoped service
builder.Services.AddScoped<ITodoRepository, TodoRepository>();
var app = builder.Build();.NET 5
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureHostOptions(o => o.ShutdownTimeout = TimeSpan.FromSeconds(30));
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});Existing extension methods on IHostBuilder can be accessed using the Host property.
.NET 6
var builder = WebApplication.CreateBuilder(args);
// Wait 30 seconds for graceful shutdown
builder.Host.ConfigureHostOptions(o => o.ShutdownTimeout = TimeSpan.FromSeconds(30));
var app = builder.Build();.NET 5
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
// Change the HTTP server implemenation to be HTTP.sys based
webBuilder.UseHttpSys()
.UseStartup<Startup>();
});.NET 6
Existing extension methods on IWebHostBuilder can be accessed using the WebHost property.
var builder = WebApplication.CreateBuilder(args);
// Change the HTTP server implemenation to be HTTP.sys based
builder.WebHost.UseHttpSys();
var app = builder.Build();By default, the web root is relative to the content root in the wwwroot folder. This is where the static files
middleware expects to find static files. You can change this by using the UseWebRoot method on the WebHost property:
.NET 5
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
// Look for static files in webroot
webBuilder.UseWebRoot("webroot")
.UseStartup<Startup>();
});.NET 6
var builder = WebApplication.CreateBuilder(args);
// Look for static files in webroot
builder.WebHost.UseWebRoot("webroot");
var app = builder.Build();This example uses Autofac
.NET 5
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});public class Startup
{
public void ConfigureContainer(ContainerBuilder containerBuilder)
{
}
}.NET 6
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
// Register your own things directly with Autofac here. Don't
// call builder.Populate(), that happens in AutofacServiceProviderFactory
// for you.
builder.Host.ConfigureContainer<ContainerBuilder>(builder => builder.RegisterModule(new MyApplicationModule()));
var app = builder.Build();