ASP.NET Core fundamentals overview

Note

This isn't the latest version of this article. For the current release, see the .NET 9 version of this article.

Warning

This version of ASP.NET Core is no longer supported. For more information, see the .NET and .NET Core Support Policy. For the current release, see the .NET 9 version of this article.

Important

This information relates to a pre-release product that may be substantially modified before it's commercially released. Microsoft makes no warranties, express or implied, with respect to the information provided here.

For the current release, see the .NET 9 version of this article.

This article provides an overview of the fundamentals for building ASP.NET Core apps, including dependency injection (DI), configuration, middleware, and more.

For Blazor fundamentals guidance, which adds to or supersedes the guidance in this article, see ASP.NET Core Blazor fundamentals.

Program.cs

ASP.NET Core apps created with the web templates contain the application startup code in the Program.cs file. The Program.cs file is where:

  • Services required by the app are configured.
  • The app's request handling pipeline is defined as a series of middleware components.

The following app startup code supports several app types:

using WebAll.Components;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapGet("/hi", () => "Hello!");

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode();

app.UseAntiforgery();

app.Run();

Dependency injection (services)

ASP.NET Core features built-in dependency injection (DI) that makes configured services available throughout an app. Services are added to the DI container with WebApplicationBuilder.Services, builder.Services in the preceding code. When the WebApplicationBuilder is instantiated, many framework-provided services are added automatically. builder is a WebApplicationBuilder in the following code:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

In the preceding code, CreateBuilder adds configuration, logging, and many other services to the DI container. The DI framework provides an instance of a requested service at run time.

The following code adds a custom DbContext and Blazor components to the DI container:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContextFactory<BlazorWebAppMoviesContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("MoviesContext") 
        ?? throw new InvalidOperationException("Connection string not found.")));

builder.Services.AddQuickGridEntityFrameworkAdapter();

builder.Services.AddDatabaseDeveloperPageExceptionFilter();

// Add services to the container.
builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();

var app = builder.Build();

In Blazor Web Apps, services are often resolved from DI at run time by using the @inject directive in a Razor component, as shown in the following example:

@page "/movies"
@rendermode InteractiveServer
@using Microsoft.EntityFrameworkCore
@using Microsoft.AspNetCore.Components.QuickGrid
@using BlazorWebAppMovies.Models
@using BlazorWebAppMovies.Data
@implements IAsyncDisposable
@inject IDbContextFactory<BlazorWebAppMovies.Data.BlazorWebAppMoviesContext> DbFactory

<PageTitle>Index</PageTitle>

<h1>Index</h1>

<div>
    <input type="search" @bind="titleFilter" @bind:event="oninput" />
</div>

<p>
    <a href="movies/create">Create New</a>
</p>

<QuickGrid Class="table" Items="FilteredMovies" Pagination="pagination">
    <PropertyColumn Property="movie => movie.Title" Sortable="true" />
    <PropertyColumn Property="movie => movie.ReleaseDate" Title="Release Date" />
    <PropertyColumn Property="movie => movie.Genre" />
    <PropertyColumn Property="movie => movie.Price" />
    <PropertyColumn Property="movie => movie.Rating" />

    <TemplateColumn Context="movie">
        <a href="@($"movies/edit?id={movie.Id}")">Edit</a> |
        <a href="@($"movies/details?id={movie.Id}")">Details</a> |
        <a href="@($"movies/delete?id={movie.Id}")">Delete</a>
    </TemplateColumn>
</QuickGrid>

<Paginator State="pagination" />

@code {
    private BlazorWebAppMoviesContext context = default!;
    private PaginationState pagination = new PaginationState { ItemsPerPage = 10 };
    private string titleFilter = string.Empty;

    private IQueryable<Movie> FilteredMovies =>
        context.Movie.Where(m => m.Title!.Contains(titleFilter));

    protected override void OnInitialized()
    {
        context = DbFactory.CreateDbContext();
    }

    public async ValueTask DisposeAsync() => await context.DisposeAsync();
}

In the preceding code:

  • The @inject directive is used.
  • The service is resolved in the OnInitialized method and assigned to the context variable.
  • The context service creates the FilteredMovie list.

Another way to resolve a service from DI is by using constructor injection. The following Razor Pages code uses constructor injection to resolve the database context and a logger from DI:

public class IndexModel : PageModel
{
    private readonly RazorPagesMovieContext _context;
    private readonly ILogger<IndexModel> _logger;

    public IndexModel(RazorPagesMovieContext context, ILogger<IndexModel> logger)
    {
        _context = context;
        _logger = logger;
    }

    public IList<Movie> Movie { get;set; }

    public async Task OnGetAsync()
    {
        _logger.LogInformation("IndexModel OnGetAsync.");
        Movie = await _context.Movie.ToListAsync();
    }
}

In the preceding code, the IndexModel constructor takes a parameter of type RazorPagesMovieContext, which is resolved at run time into the _context variable. The context object is used to create a list of movies in the OnGetAsync method.

For more information, see ASP.NET Core Blazor dependency injection and Dependency injection in ASP.NET Core.

Middleware

The request handling pipeline is composed as a series of middleware components. Each component performs operations on an HttpContext and either invokes the next middleware in the pipeline or terminates the request.

By convention, a middleware component is added to the pipeline by invoking a Use{Feature} extension method. The use of methods named Use{Feature} to add middleware to an app is illustrated in the following code:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContextFactory<BlazorWebAppMoviesContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("MoviesContext") 
        ?? throw new InvalidOperationException("Connection string not found.")));

builder.Services.AddQuickGridEntityFrameworkAdapter();

builder.Services.AddDatabaseDeveloperPageExceptionFilter();

// Add services to the container.
builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();

var app = builder.Build();

using (var scope = app.Services.CreateScope())
{
    var services = scope.ServiceProvider;

    SeedData.Initialize(services);
}

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error", createScopeForErrors: true);
    app.UseHsts();
    app.UseMigrationsEndPoint();
}
app.UseHttpsRedirection();

app.UseAntiforgery();

app.MapStaticAssets();
app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode();

app.Run();

For more information, see ASP.NET Core Middleware.

Host

On startup, an ASP.NET Core app builds a host. The host encapsulates all of the app's resources, such as:

  • An HTTP server implementation
  • Middleware components
  • Logging
  • Dependency injection (DI) services
  • Configuration

There are three different hosts capable of running an ASP.NET Core app:

The ASP.NET Core WebApplication and WebApplicationBuilder types are recommended and are used in all the ASP.NET Core templates. WebApplication behaves similarly to the .NET Generic Host and exposes many of the same interfaces but requires fewer callbacks to configure. The ASP.NET Core WebHost is available only for backward compatibility.

The following example instantiates a WebApplication and assigns it to a variable named app:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContextFactory<BlazorWebAppMoviesContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("MoviesContext") 
        ?? throw new InvalidOperationException("Connection string not found.")));

builder.Services.AddQuickGridEntityFrameworkAdapter();

builder.Services.AddDatabaseDeveloperPageExceptionFilter();

// Add services to the container.
builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();

var app = builder.Build();

The WebApplicationBuilder.Build method configures a host with a set of default options, such as:

  • Use Kestrel as the web server and enable IIS integration.
  • Load configuration from appsettings.json, environment variables, command line arguments, and other configuration sources.
  • Send logging output to the console and debug providers.

Non-web scenarios

The Generic Host enables other types of apps to use cross-cutting framework extensions, such as logging, dependency injection (DI), configuration, and app lifetime management. For more information, see .NET Generic Host in ASP.NET Core and Background tasks with hosted services in ASP.NET Core.

Servers

An ASP.NET Core app uses an HTTP server implementation to listen for HTTP requests. The server surfaces requests to the app as a set of request features composed into an HttpContext.

ASP.NET Core provides the following server implementations:

  • Kestrel is a cross-platform web server. Kestrel is often run in a reverse proxy configuration using IIS. In ASP.NET Core 2.0 and later, Kestrel can be run as a public-facing edge server exposed directly to the Internet.
  • IIS HTTP Server is a server for Windows that uses IIS. With this server, the ASP.NET Core app and IIS run in the same process.
  • HTTP.sys is a server for Windows that isn't used with IIS.

For more information, see Web server implementations in ASP.NET Core.

Configuration

ASP.NET Core provides a configuration framework that gets settings as name-value pairs from an ordered set of configuration providers. Built-in configuration providers are available for a variety of sources, such as .json files, .xml files, environment variables, and command-line arguments. Write custom configuration providers to support other sources.

By default, ASP.NET Core apps are configured to read from appsettings.json, environment variables, the command line, and more. When the app's configuration is loaded, values from environment variables override values from appsettings.json.

For managing confidential configuration data such as passwords in the development environment, .NET Core provides the Secret Manager. For production secrets, we recommend Azure Key Vault.

For more information, see Configuration in ASP.NET Core.

Environments

Execution environments, such as Development, Staging, and Production, are available in ASP.NET Core. Specify the environment an app is running in by setting the ASPNETCORE_ENVIRONMENT environment variable. ASP.NET Core reads that environment variable at app startup and stores the value in an IWebHostEnvironment implementation. This implementation is available anywhere in an app via dependency injection (DI).

The following example configures the exception handler and HTTP Strict Transport Security Protocol (HSTS) middleware when not running in the Development environment:

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error", createScopeForErrors: true);
    app.UseHsts();
    app.UseMigrationsEndPoint();
}

For more information, see Use multiple environments in ASP.NET Core.

Logging

ASP.NET Core supports a logging API that works with a variety of built-in and third-party logging providers. Available providers include:

  • Console
  • Debug
  • Event Tracing on Windows
  • Windows Event Log
  • TraceSource
  • Azure App Service
  • Azure Application Insights

To create logs, resolve an ILogger<TCategoryName> service from dependency injection (DI) and call logging methods such as LogInformation. The following example shows how to get and use a logger in a .razor file for a page in a Blazor Web App. A logger object and a console provider for it are stored in the DI container automatically when the CreateBuilder method is called in Program.cs.

@page "/weather"
@attribute [StreamRendering]
@inject ILogger<Weather> Logger

<PageTitle>Weather</PageTitle>

<h1>Weather</h1>

<p>This component demonstrates showing data and logging.</p>

@if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Date</th>
                <th aria-label="Temperature in Celsius">Temp. (C)</th>
                <th aria-label="Temperature in Farenheit">Temp. (F)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var forecast in forecasts)
            {
                <tr>
                    <td>@forecast.Date.ToShortDateString()</td>
                    <td>@forecast.TemperatureC</td>
                    <td>@forecast.TemperatureF</td>
                    <td>@forecast.Summary</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private WeatherForecast[]? forecasts;

    protected override async Task OnInitializedAsync()
    {
        // Simulate asynchronous loading to demonstrate streaming rendering
       
        await Task.Delay(500);

        Logger.LogInformation("This is an information log message.");
        Logger.LogWarning("This is a warning log message.");
        Logger.LogError("This is an error log message.");

        var startDate = DateOnly.FromDateTime(DateTime.Now);
        var summaries = new[] { "Freezing", "Bracing", "Chilly",
            "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
        forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = startDate.AddDays(index),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = summaries[Random.Shared.Next(summaries.Length)]
        }).ToArray();
    }

    private class WeatherForecast
    {
        public DateOnly Date { get; set; }
        public int TemperatureC { get; set; }
        public string? Summary { get; set; }
        public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
    }
}

For more information, see Logging in .NET Core and ASP.NET Core.

Routing

Routing in ASP.NET Core is a mechanism that maps incoming requests to specific endpoints in an application. It enables you to define URL patterns that correspond to different components, such as Blazor components, Razor pages, MVC controller actions, or middleware.

The UseRouting(IApplicationBuilder) method adds routing middleware to the request pipeline. This middleware processes the routing information and determines the appropriate endpoint for each request. You don't have to explicitly call UseRouting unless you want to change the order in which middleware is processed.

For more information, see Routing in ASP.NET Core and ASP.NET Core Blazor routing and navigation.

Error handling

ASP.NET Core has built-in features for handling errors, such as:

  • A developer exception page
  • Custom error pages
  • Static status code pages
  • Startup exception handling

For more information, see Handle errors in ASP.NET Core.

Make HTTP requests

An implementation of IHttpClientFactory is available for creating HttpClient instances. The factory:

  • Provides a central location for naming and configuring logical HttpClient instances. For example, register and configure a github client for accessing GitHub. Register and configure a default client for other purposes.
  • Supports registration and chaining of multiple delegating handlers to build an outgoing request middleware pipeline. This pattern is similar to ASP.NET Core's inbound middleware pipeline. The pattern provides a mechanism to manage cross-cutting concerns for HTTP requests, including caching, error handling, serialization, and logging.
  • Integrates with Polly, a popular third-party library for transient fault handling.
  • Manages the pooling and lifetime of underlying HttpClientHandler instances to avoid common DNS problems that occur when managing HttpClient lifetimes manually.
  • Adds a configurable logging experience via ILogger for all requests sent through clients created by the factory.

For more information, see Make HTTP requests using IHttpClientFactory in ASP.NET Core.

Content root

The content root is the base path for:

  • The executable hosting the app (.exe).
  • Compiled assemblies that make up the app (.dll).
  • Content files used by the app, such as:
    • Razor files (.cshtml, .razor)
    • Configuration files (.json, .xml)
    • Data files (.db)
  • The Web root, typically the wwwroot folder.

During development, the content root defaults to the project's root directory. This directory is also the base path for both the app's content files and the Web root. Specify a different content root by setting its path when building the host. For more information, see Content root.

Web root

The web root is the base path for public, static resource files, such as:

  • Stylesheets (.css)
  • JavaScript (.js)
  • Images (.png, .jpg)

By default, static files are served only from the web root directory and its sub-directories. The web root path defaults to {content root}/wwwroot. Specify a different web root by setting its path when building the host. For more information, see Web root.

Prevent publishing files in wwwroot with the <Content> project item in the project file. The following example prevents publishing content in wwwroot/local and its sub-directories:

<ItemGroup>
  <Content Update="wwwroot\local\**\*.*" CopyToPublishDirectory="Never" />
</ItemGroup>

In Razor .cshtml files, ~/ points to the web root. A path beginning with ~/ is referred to as a virtual path.

For more information, see Static files in ASP.NET Core.

Additional resources

This article provides an overview of the fundamentals for building ASP.NET Core apps, including dependency injection (DI), configuration, middleware, and more.

Program.cs

ASP.NET Core apps created with the web templates contain the application startup code in the Program.cs file. The Program.cs file is where:

  • Services required by the app are configured.
  • The app's request handling pipeline is defined as a series of middleware components.

The following app startup code supports:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapGet("/hi", () => "Hello!");

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Dependency injection (services)

ASP.NET Core includes dependency injection (DI) that makes configured services available throughout an app. Services are added to the DI container with WebApplicationBuilder.Services, builder.Services in the preceding code. When the WebApplicationBuilder is instantiated, many framework-provided services are added. builder is a WebApplicationBuilder in the following code:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

In the preceding highlighted code, builder has configuration, logging, and many other services added to the DI container.

The following code adds Razor Pages, MVC controllers with views, and a custom DbContext to the DI container:

using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Data;
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDbContext<RazorPagesMovieContext>(options =>
   options.UseSqlServer(builder.Configuration.GetConnectionString("RPMovieContext")));

var app = builder.Build();

Services are typically resolved from DI using constructor injection. The DI framework provides an instance of this service at runtime.

The following code uses constructor injection to resolve the database context and logger from DI:

public class IndexModel : PageModel
{
    private readonly RazorPagesMovieContext _context;
    private readonly ILogger<IndexModel> _logger;

    public IndexModel(RazorPagesMovieContext context, ILogger<IndexModel> logger)
    {
        _context = context;
        _logger = logger;
    }

    public IList<Movie> Movie { get;set; }

    public async Task OnGetAsync()
    {
        _logger.LogInformation("IndexModel OnGetAsync.");
        Movie = await _context.Movie.ToListAsync();
    }
}

Middleware

The request handling pipeline is composed as a series of middleware components. Each component performs operations on an HttpContext and either invokes the next middleware in the pipeline or terminates the request.

By convention, a middleware component is added to the pipeline by invoking a Use{Feature} extension method. Middleware added to the app is highlighted in the following code:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapGet("/hi", () => "Hello!");

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

For more information, see ASP.NET Core Middleware.

Host

On startup, an ASP.NET Core app builds a host. The host encapsulates all of the app's resources, such as:

  • An HTTP server implementation
  • Middleware components
  • Logging
  • Dependency injection (DI) services
  • Configuration

There are three different hosts capable of running an ASP.NET Core app:

The ASP.NET Core WebApplication and WebApplicationBuilder types are recommended and used in all the ASP.NET Core templates. WebApplication behaves similarly to the .NET Generic Host and exposes many of the same interfaces but requires less callbacks to configure. The ASP.NET Core WebHost is available only for backward compatibility.

The following example instantiates a WebApplication:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

The WebApplicationBuilder.Build method configures a host with a set of default options, such as:

  • Use Kestrel as the web server and enable IIS integration.
  • Load configuration from appsettings.json, environment variables, command line arguments, and other configuration sources.
  • Send logging output to the console and debug providers.

Non-web scenarios

The Generic Host allows other types of apps to use cross-cutting framework extensions, such as logging, dependency injection (DI), configuration, and app lifetime management. For more information, see .NET Generic Host in ASP.NET Core and Background tasks with hosted services in ASP.NET Core.

Servers

An ASP.NET Core app uses an HTTP server implementation to listen for HTTP requests. The server surfaces requests to the app as a set of request features composed into an HttpContext.

ASP.NET Core provides the following server implementations:

  • Kestrel is a cross-platform web server. Kestrel is often run in a reverse proxy configuration using IIS. In ASP.NET Core 2.0 or later, Kestrel can be run as a public-facing edge server exposed directly to the Internet.
  • IIS HTTP Server is a server for Windows that uses IIS. With this server, the ASP.NET Core app and IIS run in the same process.
  • HTTP.sys is a server for Windows that isn't used with IIS.

For more information, see Web server implementations in ASP.NET Core.

Configuration

ASP.NET Core provides a configuration framework that gets settings as name-value pairs from an ordered set of configuration providers. Built-in configuration providers are available for a variety of sources, such as .json files, .xml files, environment variables, and command-line arguments. Write custom configuration providers to support other sources.

By default, ASP.NET Core apps are configured to read from appsettings.json, environment variables, the command line, and more. When the app's configuration is loaded, values from environment variables override values from appsettings.json.

For managing confidential configuration data such as passwords, .NET Core provides the Secret Manager. For production secrets, we recommend Azure Key Vault.

For more information, see Configuration in ASP.NET Core.

Environments

Execution environments, such as Development, Staging, and Production, are available in ASP.NET Core. Specify the environment an app is running in by setting the ASPNETCORE_ENVIRONMENT environment variable. ASP.NET Core reads that environment variable at app startup and stores the value in an IWebHostEnvironment implementation. This implementation is available anywhere in an app via dependency injection (DI).

The following example configures the exception handler and HTTP Strict Transport Security Protocol (HSTS) middleware when not running in the Development environment:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapGet("/hi", () => "Hello!");

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

For more information, see Use multiple environments in ASP.NET Core.

Logging

ASP.NET Core supports a logging API that works with a variety of built-in and third-party logging providers. Available providers include:

  • Console
  • Debug
  • Event Tracing on Windows
  • Windows Event Log
  • TraceSource
  • Azure App Service
  • Azure Application Insights

To create logs, resolve an ILogger<TCategoryName> service from dependency injection (DI) and call logging methods such as LogInformation. For example:

public class IndexModel : PageModel
{
    private readonly RazorPagesMovieContext _context;
    private readonly ILogger<IndexModel> _logger;

    public IndexModel(RazorPagesMovieContext context, ILogger<IndexModel> logger)
    {
        _context = context;
        _logger = logger;
    }

    public IList<Movie> Movie { get;set; }

    public async Task OnGetAsync()
    {
        _logger.LogInformation("IndexModel OnGetAsync.");
        Movie = await _context.Movie.ToListAsync();
    }
}

For more information, see Logging in .NET Core and ASP.NET Core.

Routing

A route is a URL pattern that is mapped to a handler. The handler is typically a Razor page, an action method in an MVC controller, or a middleware. ASP.NET Core routing gives you control over the URLs used by your app.

The following code, generated by the ASP.NET Core web application template, calls UseRouting:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

For more information, see Routing in ASP.NET Core.

Error handling

ASP.NET Core has built-in features for handling errors, such as:

  • A developer exception page
  • Custom error pages
  • Static status code pages
  • Startup exception handling

For more information, see Handle errors in ASP.NET Core.

Make HTTP requests

An implementation of IHttpClientFactory is available for creating HttpClient instances. The factory:

  • Provides a central location for naming and configuring logical HttpClient instances. For example, register and configure a github client for accessing GitHub. Register and configure a default client for other purposes.
  • Supports registration and chaining of multiple delegating handlers to build an outgoing request middleware pipeline. This pattern is similar to ASP.NET Core's inbound middleware pipeline. The pattern provides a mechanism to manage cross-cutting concerns for HTTP requests, including caching, error handling, serialization, and logging.
  • Integrates with Polly, a popular third-party library for transient fault handling.
  • Manages the pooling and lifetime of underlying HttpClientHandler instances to avoid common DNS problems that occur when managing HttpClient lifetimes manually.
  • Adds a configurable logging experience via ILogger for all requests sent through clients created by the factory.

For more information, see Make HTTP requests using IHttpClientFactory in ASP.NET Core.

Content root

The content root is the base path for:

  • The executable hosting the app (.exe).
  • Compiled assemblies that make up the app (.dll).
  • Content files used by the app, such as:
    • Razor files (.cshtml, .razor)
    • Configuration files (.json, .xml)
    • Data files (.db)
  • The Web root, typically the wwwroot folder.

During development, the content root defaults to the project's root directory. This directory is also the base path for both the app's content files and the Web root. Specify a different content root by setting its path when building the host. For more information, see Content root.

Web root

The web root is the base path for public, static resource files, such as:

  • Stylesheets (.css)
  • JavaScript (.js)
  • Images (.png, .jpg)

By default, static files are served only from the web root directory and its sub-directories. The web root path defaults to {content root}/wwwroot. Specify a different web root by setting its path when building the host. For more information, see Web root.

Prevent publishing files in wwwroot with the <Content> project item in the project file. The following example prevents publishing content in wwwroot/local and its sub-directories:

<ItemGroup>
  <Content Update="wwwroot\local\**\*.*" CopyToPublishDirectory="Never" />
</ItemGroup>

In Razor .cshtml files, ~/ points to the web root. A path beginning with ~/ is referred to as a virtual path.

For more information, see Static files in ASP.NET Core.

Additional resources

This article provides an overview of the fundamentals for building ASP.NET Core apps, including dependency injection (DI), configuration, middleware, and more.

The Startup class

The Startup class is where:

  • Services required by the app are configured.
  • The app's request handling pipeline is defined, as a series of middleware components.

Here's a sample Startup class:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<RazorPagesMovieContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("RazorPagesMovieContext")));

        services.AddControllersWithViews();
        services.AddRazorPages();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapDefaultControllerRoute();
            endpoints.MapRazorPages();
        });
    }
}

For more information, see App startup in ASP.NET Core.

Dependency injection (services)

ASP.NET Core includes a built-in dependency injection (DI) framework that makes configured services available throughout an app. For example, a logging component is a service.

Code to configure (or register) services is added to the Startup.ConfigureServices method. For example:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<RazorPagesMovieContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("RazorPagesMovieContext")));

    services.AddControllersWithViews();
    services.AddRazorPages();
}

Services are typically resolved from DI using constructor injection. With constructor injection, a class declares a constructor parameter of either the required type or an interface. The DI framework provides an instance of this service at runtime.

The following example uses constructor injection to resolve a RazorPagesMovieContext from DI:

public class IndexModel : PageModel
{
    private readonly RazorPagesMovieContext _context;

    public IndexModel(RazorPagesMovieContext context)
    {
        _context = context;
    }

    // ...

    public async Task OnGetAsync()
    {
        Movies = await _context.Movies.ToListAsync();
    }
}

If the built-in Inversion of Control (IoC) container doesn't meet all of an app's needs, a third-party IoC container can be used instead.

For more information, see Dependency injection in ASP.NET Core.

Middleware

The request handling pipeline is composed as a series of middleware components. Each component performs operations on an HttpContext and either invokes the next middleware in the pipeline or terminates the request.

By convention, a middleware component is added to the pipeline by invoking a Use... extension method in the Startup.Configure method. For example, to enable rendering of static files, call UseStaticFiles.

The following example configures a request handling pipeline:

public void Configure(IApplicationBuilder app)
{
    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
        endpoints.MapRazorPages();
    });
}

ASP.NET Core includes a rich set of built-in middleware. Custom middleware components can also be written.

For more information, see ASP.NET Core Middleware.

Host

On startup, an ASP.NET Core app builds a host. The host encapsulates all of the app's resources, such as:

  • An HTTP server implementation
  • Middleware components
  • Logging
  • Dependency injection (DI) services
  • Configuration

There are two different hosts:

  • .NET Generic Host
  • ASP.NET Core Web Host

The .NET Generic Host is recommended. The ASP.NET Core Web Host is available only for backwards compatibility.

The following example creates a .NET Generic Host:

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>();
            });
}

The CreateDefaultBuilder and ConfigureWebHostDefaults methods configure a host with a set of default options, such as:

  • Use Kestrel as the web server and enable IIS integration.
  • Load configuration from appsettings.json, appsettings.{Environment}.json, environment variables, command line arguments, and other configuration sources.
  • Send logging output to the console and debug providers.

For more information, see .NET Generic Host in ASP.NET Core.

Non-web scenarios

The Generic Host allows other types of apps to use cross-cutting framework extensions, such as logging, dependency injection (DI), configuration, and app lifetime management. For more information, see .NET Generic Host in ASP.NET Core and Background tasks with hosted services in ASP.NET Core.

Servers

An ASP.NET Core app uses an HTTP server implementation to listen for HTTP requests. The server surfaces requests to the app as a set of request features composed into an HttpContext.

ASP.NET Core provides the following server implementations:

  • Kestrel is a cross-platform web server. Kestrel is often run in a reverse proxy configuration using IIS. In ASP.NET Core 2.0 or later, Kestrel can be run as a public-facing edge server exposed directly to the Internet.
  • IIS HTTP Server is a server for Windows that uses IIS. With this server, the ASP.NET Core app and IIS run in the same process.
  • HTTP.sys is a server for Windows that isn't used with IIS.

For more information, see Web server implementations in ASP.NET Core.

Configuration

ASP.NET Core provides a configuration framework that gets settings as name-value pairs from an ordered set of configuration providers. Built-in configuration providers are available for a variety of sources, such as .json files, .xml files, environment variables, and command-line arguments. Write custom configuration providers to support other sources.

By default, ASP.NET Core apps are configured to read from appsettings.json, environment variables, the command line, and more. When the app's configuration is loaded, values from environment variables override values from appsettings.json.

The preferred way to read related configuration values is using the options pattern. For more information, see Bind hierarchical configuration data using the options pattern.

For managing confidential configuration data such as passwords, .NET Core provides the Secret Manager. For production secrets, we recommend Azure Key Vault.

For more information, see Configuration in ASP.NET Core.

Environments

Execution environments, such as Development, Staging, and Production, are a first-class notion in ASP.NET Core. Specify the environment an app is running in by setting the ASPNETCORE_ENVIRONMENT environment variable. ASP.NET Core reads that environment variable at app startup and stores the value in an IWebHostEnvironment implementation. This implementation is available anywhere in an app via dependency injection (DI).

The following example configures the app to provide detailed error information when running in the Development environment:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
        endpoints.MapRazorPages();
    });
}

For more information, see Use multiple environments in ASP.NET Core.

Logging

ASP.NET Core supports a logging API that works with a variety of built-in and third-party logging providers. Available providers include:

  • Console
  • Debug
  • Event Tracing on Windows
  • Windows Event Log
  • TraceSource
  • Azure App Service
  • Azure Application Insights

To create logs, resolve an ILogger<TCategoryName> service from dependency injection (DI) and call logging methods such as LogInformation. For example:

public class TodoController : ControllerBase
{
    private readonly ILogger _logger;

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

    [HttpGet("{id}", Name = "GetTodo")]
    public ActionResult<TodoItem> GetById(string id)
    {
        _logger.LogInformation(LoggingEvents.GetItem, "Getting item {Id}", id);
        
        // Item lookup code removed.
        
        if (item == null)
        {
            _logger.LogWarning(LoggingEvents.GetItemNotFound, "GetById({Id}) NOT FOUND", id);
            return NotFound();
        }
        
        return item;
    }
}

Logging methods such as LogInformation support any number of fields. These fields are commonly used to construct a message string, but some logging providers send these to a data store as separate fields. This feature makes it possible for logging providers to implement semantic logging, also known as structured logging.

For more information, see Logging in .NET Core and ASP.NET Core.

Routing

A route is a URL pattern that is mapped to a handler. The handler is typically a Razor page, an action method in an MVC controller, or a middleware. ASP.NET Core routing gives you control over the URLs used by your app.

For more information, see Routing in ASP.NET Core.

Error handling

ASP.NET Core has built-in features for handling errors, such as:

  • A developer exception page
  • Custom error pages
  • Static status code pages
  • Startup exception handling

For more information, see Handle errors in ASP.NET Core.

Make HTTP requests

An implementation of IHttpClientFactory is available for creating HttpClient instances. The factory:

  • Provides a central location for naming and configuring logical HttpClient instances. For example, register and configure a github client for accessing GitHub. Register and configure a default client for other purposes.
  • Supports registration and chaining of multiple delegating handlers to build an outgoing request middleware pipeline. This pattern is similar to ASP.NET Core's inbound middleware pipeline. The pattern provides a mechanism to manage cross-cutting concerns for HTTP requests, including caching, error handling, serialization, and logging.
  • Integrates with Polly, a popular third-party library for transient fault handling.
  • Manages the pooling and lifetime of underlying HttpClientHandler instances to avoid common DNS problems that occur when managing HttpClient lifetimes manually.
  • Adds a configurable logging experience via ILogger for all requests sent through clients created by the factory.

For more information, see Make HTTP requests using IHttpClientFactory in ASP.NET Core.

Content root

The content root is the base path for:

  • The executable hosting the app (.exe).
  • Compiled assemblies that make up the app (.dll).
  • Content files used by the app, such as:
    • Razor files (.cshtml, .razor)
    • Configuration files (.json, .xml)
    • Data files (.db)
  • The Web root, typically the wwwroot folder.

During development, the content root defaults to the project's root directory. This directory is also the base path for both the app's content files and the Web root. Specify a different content root by setting its path when building the host. For more information, see Content root.

Web root

The web root is the base path for public, static resource files, such as:

  • Stylesheets (.css)
  • JavaScript (.js)
  • Images (.png, .jpg)

By default, static files are served only from the web root directory and its sub-directories. The web root path defaults to {content root}/wwwroot. Specify a different web root by setting its path when building the host. For more information, see Web root.

Prevent publishing files in wwwroot with the <Content> project item in the project file. The following example prevents publishing content in wwwroot/local and its sub-directories:

<ItemGroup>
  <Content Update="wwwroot\local\**\*.*" CopyToPublishDirectory="Never" />
</ItemGroup>

In Razor .cshtml files, tilde-slash (~/) points to the web root. A path beginning with ~/ is referred to as a virtual path.

For more information, see Static files in ASP.NET Core.

This article provides an overview of the fundamentals for building ASP.NET Core apps, including dependency injection (DI), configuration, middleware, and more.

For Blazor fundamentals guidance, which adds to or supersedes the guidance in this node, see ASP.NET Core Blazor fundamentals.

Program.cs

ASP.NET Core apps created with the web templates contain the application startup code in the Program.cs file. The Program.cs file is where:

  • Services required by the app are configured.
  • The app's request handling pipeline is defined as a series of middleware components.

The following app startup code supports:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapGet("/hi", () => "Hello!");

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Dependency injection (services)

ASP.NET Core includes dependency injection (DI) that makes configured services available throughout an app. Services are added to the DI container with WebApplicationBuilder.Services, builder.Services in the preceding code. When the WebApplicationBuilder is instantiated, many framework-provided services are added. builder is a WebApplicationBuilder in the following code:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

In the preceding highlighted code, builder has configuration, logging, and many other services added to the DI container.

The following code adds Razor Pages, MVC controllers with views, and a custom DbContext to the DI container:

using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Data;
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDbContext<RazorPagesMovieContext>(options =>
   options.UseSqlServer(builder.Configuration.GetConnectionString("RPMovieContext")));

var app = builder.Build();

Services are typically resolved from DI using constructor injection. The DI framework provides an instance of this service at runtime.

The following code uses constructor injection to resolve the database context and logger from DI:

public class IndexModel : PageModel
{
    private readonly RazorPagesMovieContext _context;
    private readonly ILogger<IndexModel> _logger;

    public IndexModel(RazorPagesMovieContext context, ILogger<IndexModel> logger)
    {
        _context = context;
        _logger = logger;
    }

    public IList<Movie> Movie { get;set; }

    public async Task OnGetAsync()
    {
        _logger.LogInformation("IndexModel OnGetAsync.");
        Movie = await _context.Movie.ToListAsync();
    }
}

Middleware

The request handling pipeline is composed as a series of middleware components. Each component performs operations on an HttpContext and either invokes the next middleware in the pipeline or terminates the request.

By convention, a middleware component is added to the pipeline by invoking a Use{Feature} extension method. Middleware added to the app is highlighted in the following code:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapGet("/hi", () => "Hello!");

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

For more information, see ASP.NET Core Middleware.

Host

On startup, an ASP.NET Core app builds a host. The host encapsulates all of the app's resources, such as:

  • An HTTP server implementation
  • Middleware components
  • Logging
  • Dependency injection (DI) services
  • Configuration

There are three different hosts capable of running an ASP.NET Core app:

The ASP.NET Core WebApplication and WebApplicationBuilder types are recommended and used in all the ASP.NET Core templates. WebApplication behaves similarly to the .NET Generic Host and exposes many of the same interfaces but requires less callbacks to configure. The ASP.NET Core WebHost is available only for backward compatibility.

The following example instantiates a WebApplication:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

The WebApplicationBuilder.Build method configures a host with a set of default options, such as:

  • Use Kestrel as the web server and enable IIS integration.
  • Load configuration from appsettings.json, environment variables, command line arguments, and other configuration sources.
  • Send logging output to the console and debug providers.

Non-web scenarios

The Generic Host allows other types of apps to use cross-cutting framework extensions, such as logging, dependency injection (DI), configuration, and app lifetime management. For more information, see .NET Generic Host in ASP.NET Core and Background tasks with hosted services in ASP.NET Core.

Servers

An ASP.NET Core app uses an HTTP server implementation to listen for HTTP requests. The server surfaces requests to the app as a set of request features composed into an HttpContext.

ASP.NET Core provides the following server implementations:

  • Kestrel is a cross-platform web server. Kestrel is often run in a reverse proxy configuration using IIS. In ASP.NET Core 2.0 or later, Kestrel can be run as a public-facing edge server exposed directly to the Internet.
  • IIS HTTP Server is a server for Windows that uses IIS. With this server, the ASP.NET Core app and IIS run in the same process.
  • HTTP.sys is a server for Windows that isn't used with IIS.

For more information, see Web server implementations in ASP.NET Core.

Configuration

ASP.NET Core provides a configuration framework that gets settings as name-value pairs from an ordered set of configuration providers. Built-in configuration providers are available for a variety of sources, such as .json files, .xml files, environment variables, and command-line arguments. Write custom configuration providers to support other sources.

By default, ASP.NET Core apps are configured to read from appsettings.json, environment variables, the command line, and more. When the app's configuration is loaded, values from environment variables override values from appsettings.json.

For managing confidential configuration data such as passwords, .NET Core provides the Secret Manager. For production secrets, we recommend Azure Key Vault.

For more information, see Configuration in ASP.NET Core.

Environments

Execution environments, such as Development, Staging, and Production, are available in ASP.NET Core. Specify the environment an app is running in by setting the ASPNETCORE_ENVIRONMENT environment variable. ASP.NET Core reads that environment variable at app startup and stores the value in an IWebHostEnvironment implementation. This implementation is available anywhere in an app via dependency injection (DI).

The following example configures the exception handler and HTTP Strict Transport Security Protocol (HSTS) middleware when not running in the Development environment:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapGet("/hi", () => "Hello!");

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

For more information, see Use multiple environments in ASP.NET Core.

Logging

ASP.NET Core supports a logging API that works with a variety of built-in and third-party logging providers. Available providers include:

  • Console
  • Debug
  • Event Tracing on Windows
  • Windows Event Log
  • TraceSource
  • Azure App Service
  • Azure Application Insights

To create logs, resolve an ILogger<TCategoryName> service from dependency injection (DI) and call logging methods such as LogInformation. For example:

public class IndexModel : PageModel
{
    private readonly RazorPagesMovieContext _context;
    private readonly ILogger<IndexModel> _logger;

    public IndexModel(RazorPagesMovieContext context, ILogger<IndexModel> logger)
    {
        _context = context;
        _logger = logger;
    }

    public IList<Movie> Movie { get;set; }

    public async Task OnGetAsync()
    {
        _logger.LogInformation("IndexModel OnGetAsync.");
        Movie = await _context.Movie.ToListAsync();
    }
}

For more information, see Logging in .NET Core and ASP.NET Core.

Routing

A route is a URL pattern that is mapped to a handler. The handler is typically a Razor page, an action method in an MVC controller, or a middleware. ASP.NET Core routing gives you control over the URLs used by your app.

The following code, generated by the ASP.NET Core web application template, calls UseRouting:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

For more information, see Routing in ASP.NET Core.

Error handling

ASP.NET Core has built-in features for handling errors, such as:

  • A developer exception page
  • Custom error pages
  • Static status code pages
  • Startup exception handling

For more information, see Handle errors in ASP.NET Core.

Make HTTP requests

An implementation of IHttpClientFactory is available for creating HttpClient instances. The factory:

  • Provides a central location for naming and configuring logical HttpClient instances. For example, register and configure a github client for accessing GitHub. Register and configure a default client for other purposes.
  • Supports registration and chaining of multiple delegating handlers to build an outgoing request middleware pipeline. This pattern is similar to ASP.NET Core's inbound middleware pipeline. The pattern provides a mechanism to manage cross-cutting concerns for HTTP requests, including caching, error handling, serialization, and logging.
  • Integrates with Polly, a popular third-party library for transient fault handling.
  • Manages the pooling and lifetime of underlying HttpClientHandler instances to avoid common DNS problems that occur when managing HttpClient lifetimes manually.
  • Adds a configurable logging experience via ILogger for all requests sent through clients created by the factory.

For more information, see Make HTTP requests using IHttpClientFactory in ASP.NET Core.

Content root

The content root is the base path for:

  • The executable hosting the app (.exe).
  • Compiled assemblies that make up the app (.dll).
  • Content files used by the app, such as:
    • Razor files (.cshtml, .razor)
    • Configuration files (.json, .xml)
    • Data files (.db)
  • The Web root, typically the wwwroot folder.

During development, the content root defaults to the project's root directory. This directory is also the base path for both the app's content files and the Web root. Specify a different content root by setting its path when building the host. For more information, see Content root.

Web root

The web root is the base path for public, static resource files, such as:

  • Stylesheets (.css)
  • JavaScript (.js)
  • Images (.png, .jpg)

By default, static files are served only from the web root directory and its sub-directories. The web root path defaults to {content root}/wwwroot. Specify a different web root by setting its path when building the host. For more information, see Web root.

Prevent publishing files in wwwroot with the <Content> project item in the project file. The following example prevents publishing content in wwwroot/local and its sub-directories:

<ItemGroup>
  <Content Update="wwwroot\local\**\*.*" CopyToPublishDirectory="Never" />
</ItemGroup>

In Razor .cshtml files, ~/ points to the web root. A path beginning with ~/ is referred to as a virtual path.

For more information, see Static files in ASP.NET Core.

Additional resources