Inicio de la aplicación en ASP.NET Core

Nota

Esta no es la versión más reciente de este artículo. Para la versión actual, consulte la versión .NET 8 de este artículo.

Importante

Esta información hace referencia a un producto en versión preliminar, el cual puede sufrir importantes modificaciones antes de que se publique la versión comercial. Microsoft no proporciona ninguna garantía, expresa o implícita, con respecto a la información proporcionada aquí.

Para la versión actual, consulte la versión .NET 8 de este artículo.

Por Rick Anderson

Las aplicaciones de ASP.NET Core creadas con las plantillas web contienen el código de inicio de la aplicación en el archivo Program.cs.

El siguiente código de inicio de la aplicación admite:

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

Las aplicaciones que usan EventSource pueden medir el tiempo de inicio para comprender y optimizar el rendimiento de inicio. El evento ServerReady de Microsoft.AspNetCore.Hosting representa el punto en el que el servidor está listo para responder a las solicitudes.

Para obtener más información sobre el inicio de la aplicación, consulte Información general de los conceptos básicos de ASP.NET Core.

Extensión del inicio con filtros de inicio

Use IStartupFilter:

  • Para configurar el middleware al principio o al final de la canalización de middleware de una aplicación sin una llamada explícita a Use{Middleware}. Use IStartupFilter para agregar valores predeterminados al principio de la canalización sin registrar explícitamente el middleware predeterminado. IStartupFilter permite que otro componente llame a Use{Middleware} en nombre del creador de la aplicación.
  • Para crear una canalización de métodos Configure. IStartupFilter.Configure puede configurar middleware para que se ejecute antes o después del middleware agregado por las bibliotecas.

IStartupFilter implementa Configure, que recibe y devuelve un elemento Action<IApplicationBuilder>. IApplicationBuilder define una clase para configurar la canalización de solicitudes de una aplicación. Para más información, vea Creación de una canalización de middleware con IApplicationBuilder.

Cada instancia de IStartupFilter puede agregar uno o más middleware en la canalización de solicitudes. Los filtros se invocan en el orden en que se agregaron al contenedor de servicios. Los filtros pueden agregar middleware antes o después de pasar el control al siguiente filtro, por lo que se anexan al principio o al final de la canalización de la aplicación.

En el ejemplo siguiente, se muestra cómo registrar un componente de middleware con IStartupFilter. El componente de middleware RequestSetOptionsMiddleware establece un valor de opciones de un parámetro de cadena de consulta:

public class RequestSetOptionsMiddleware
{
    private readonly RequestDelegate _next;

    public RequestSetOptionsMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    // Test with https://localhost:5001/Privacy/?option=Hello
    public async Task Invoke(HttpContext httpContext)
    {
        var option = httpContext.Request.Query["option"];

        if (!string.IsNullOrWhiteSpace(option))
        {
            httpContext.Items["option"] = WebUtility.HtmlEncode(option);
        }

        await _next(httpContext);
    }
}

RequestSetOptionsMiddleware está configurado en las clase RequestSetOptionsStartupFilter:

namespace WebStartup.Middleware;
// <snippet1>
public class RequestSetOptionsStartupFilter : IStartupFilter
{
    public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
    {
        return builder =>
        {
            builder.UseMiddleware<RequestSetOptionsMiddleware>();
            next(builder);
        };
    }
}
// </snippet1>

IStartupFilter está registrado en Program.cs:

using WebStartup.Middleware;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddTransient<IStartupFilter,
                      RequestSetOptionsStartupFilter>();

var app = builder.Build();

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

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

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Cuando se proporciona un parámetro de cadena de consulta para option, el middleware procesa la asignación del valor antes de que el middleware de ASP.NET Core represente la respuesta:

@page
@model PrivacyModel
@{
    ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>

<p> Append query string ?option=hello</p>
Option String: @HttpContext.Items["option"];

El orden de ejecución de middleware se establece según el orden de registros de IStartupFilter:

  • Varias implementaciones de IStartupFilter pueden interactuar con los mismos objetos. Si el orden es importante, ordene los registros de servicio de IStartupFilter para que coincidan con el orden en que se deben ejecutar los middleware.

  • Las bibliotecas pueden agregar middleware con una o varias implementaciones de IStartupFilter que se ejecuten antes o después de otro middleware de aplicación registrado con IStartupFilter. Para invocar un middleware IStartupFilter antes de un middleware agregado por el elemento IStartupFilter de una biblioteca:

    • Coloque el registro del servicio antes de que la biblioteca se agregue al contenedor de servicios.
    • Para la invocación posterior, coloque el registro del servicio después de que se agregue la biblioteca.

Nota: No se puede extender la aplicación de ASP.NET Core al invalidar Configure. Para obtener más información, vea esta incidencia de GitHub.

Agregar opciones de configuración en el inicio desde un ensamblado externo

Una implementación de IHostingStartup permite agregar mejoras a una aplicación al iniciarla a partir de un ensamblado externo fuera del archivoProgram.cs de esta. Para obtener más información, consulte Uso de ensamblados de inicio de hospedaje en ASP.NET Core.

Startup, ConfigureServices y Configure

Para información sobre el uso de los métodos ConfigureServices y Configure con el modelo de hospedaje mínimo, consulte:

Las aplicaciones de ASP.NET Core creadas con las plantillas web contienen el código de inicio de la aplicación en el archivo Program.cs.

El siguiente código de inicio de la aplicación admite:

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

Para obtener más información sobre el inicio de la aplicación, consulte Información general de los conceptos básicos de ASP.NET Core.

Extensión del inicio con filtros de inicio

Use IStartupFilter:

  • Para configurar el middleware al principio o al final de la canalización de middleware de una aplicación sin una llamada explícita a Use{Middleware}. Use IStartupFilter para agregar valores predeterminados al principio de la canalización sin registrar explícitamente el middleware predeterminado. IStartupFilter permite que otro componente llame a Use{Middleware} en nombre del creador de la aplicación.
  • Para crear una canalización de métodos Configure. IStartupFilter.Configure puede configurar middleware para que se ejecute antes o después del middleware agregado por las bibliotecas.

IStartupFilter implementa Configure, que recibe y devuelve un elemento Action<IApplicationBuilder>. IApplicationBuilder define una clase para configurar la canalización de solicitudes de una aplicación. Para más información, vea Creación de una canalización de middleware con IApplicationBuilder.

Cada instancia de IStartupFilter puede agregar uno o más middleware en la canalización de solicitudes. Los filtros se invocan en el orden en que se agregaron al contenedor de servicios. Los filtros pueden agregar middleware antes o después de pasar el control al siguiente filtro, por lo que se anexan al principio o al final de la canalización de la aplicación.

En el ejemplo siguiente, se muestra cómo registrar un componente de middleware con IStartupFilter. El componente de middleware RequestSetOptionsMiddleware establece un valor de opciones de un parámetro de cadena de consulta:

public class RequestSetOptionsMiddleware
{
    private readonly RequestDelegate _next;

    public RequestSetOptionsMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    // Test with https://localhost:5001/Privacy/?option=Hello
    public async Task Invoke(HttpContext httpContext)
    {
        var option = httpContext.Request.Query["option"];

        if (!string.IsNullOrWhiteSpace(option))
        {
            httpContext.Items["option"] = WebUtility.HtmlEncode(option);
        }

        await _next(httpContext);
    }
}

RequestSetOptionsMiddleware está configurado en las clase RequestSetOptionsStartupFilter:

namespace WebStartup.Middleware;
// <snippet1>
public class RequestSetOptionsStartupFilter : IStartupFilter
{
    public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
    {
        return builder =>
        {
            builder.UseMiddleware<RequestSetOptionsMiddleware>();
            next(builder);
        };
    }
}
// </snippet1>

IStartupFilter está registrado en Program.cs:

using WebStartup.Middleware;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddTransient<IStartupFilter,
                      RequestSetOptionsStartupFilter>();

var app = builder.Build();

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

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

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Cuando se proporciona un parámetro de cadena de consulta para option, el middleware procesa la asignación del valor antes de que el middleware de ASP.NET Core represente la respuesta:

@page
@model PrivacyModel
@{
    ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>

<p> Append query string ?option=hello</p>
Option String: @HttpContext.Items["option"];

El orden de ejecución de middleware se establece según el orden de registros de IStartupFilter:

  • Varias implementaciones de IStartupFilter pueden interactuar con los mismos objetos. Si el orden es importante, ordene los registros de servicio de IStartupFilter para que coincidan con el orden en que se deben ejecutar los middleware.

  • Las bibliotecas pueden agregar middleware con una o varias implementaciones de IStartupFilter que se ejecuten antes o después de otro middleware de aplicación registrado con IStartupFilter. Para invocar un middleware IStartupFilter antes de un middleware agregado por el elemento IStartupFilter de una biblioteca:

    • Coloque el registro del servicio antes de que la biblioteca se agregue al contenedor de servicios.
    • Para la invocación posterior, coloque el registro del servicio después de que se agregue la biblioteca.

Nota: No se puede extender la aplicación de ASP.NET Core al invalidar Configure. Para más información, consulte este problema de GitHub.

Agregar opciones de configuración en el inicio desde un ensamblado externo

Una implementación de IHostingStartup permite agregar mejoras a una aplicación al iniciarla a partir de un ensamblado externo fuera del archivoProgram.cs de esta. Para obtener más información, consulte Uso de ensamblados de inicio de hospedaje en ASP.NET Core.

La clase Startup configura los servicios y la canalización de solicitudes de la aplicación.

Clase Startup

Las aplicaciones de ASP.NET Core utilizan una clase Startup, que se denomina Startup por convención. La clase Startup:

El tiempo de ejecución ASP.NET Core llama a ConfigureServices y Configure cuando la aplicación se inicia:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
    }

    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.UseAuthorization();

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

El ejemplo anterior corresponde a Razor Pages; la versión para MVC es similar.

La clase Startup se especifica cuando se crea el Startup de la aplicación. Normalmente, la clase Startup se especifica mediante la llamada al método WebHostBuilderExtensions.UseStartup/<TStartup> en el generador de 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>();
            });
}

El host proporciona servicios que están disponibles para el constructor de clase Startup. La aplicación agrega servicios adicionales a través de ConfigureServices. Los servicios de la aplicación y el host están disponibles en Configure y en toda la aplicación.

Solo se pueden insertar los tipos de servicio siguientes en el constructor Startup cuando se usa el Startup (IHostBuilder):

public class Startup
{
    private readonly IWebHostEnvironment _env;

    public Startup(IConfiguration configuration, IWebHostEnvironment env)
    {
        Configuration = configuration;
        _env = env;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        if (_env.IsDevelopment())
        {
        }
        else
        {
        }
    }
}

La mayoría de los servicios no están disponibles hasta que se llama al método Configure.

Inicio múltiple

Cuando la aplicación define clases Startup independientes para otros entornos (por ejemplo, StartupDevelopment), la clase Startup correspondiente se selecciona en tiempo de ejecución. La clase cuyo sufijo de nombre coincide con el entorno actual se establece como prioritaria. Si la aplicación se ejecuta en el entorno de desarrollo e incluye tanto la clase Startup como la clase StartupDevelopment, se utiliza la clase StartupDevelopment. Para obtener más información, consulte Uso de varios entornos.

Para obtener más información sobre el host, vea El host. Para obtener información sobre cómo controlar los errores que se producen durante el inicio, consulte Control de excepciones de inicio.

Método ConfigureServices

El método ConfigureServices es:

  • Opcional.
  • Lo llama el host antes del método Configure para configurar los servicios de la aplicación.
  • Es donde se establecen por convención las opciones de configuración.

El host puede configurar algunos servicios antes de que se llame a los métodos Startup. Para obtener más información, vea El host.

Para las características que requieren una configuración sustancial, hay métodos de extensión Add{Service} en IServiceCollection. Por ejemplo, AddDbContext, AddDefaultIdentity, AddEntityFrameworkStores y AddRazorPages:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {

        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        services.AddDefaultIdentity<IdentityUser>(
            options => options.SignIn.RequireConfirmedAccount = true)
            .AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddRazorPages();
    }

La adición de servicios al contenedor de servicios hace que estén disponibles en la aplicación y en el método Configure. Los servicios se resuelven a través de la inserción de dependencias o desde ApplicationServices.

El método Configure

El método Configure se usa para especificar la forma en que la aplicación responde a las solicitudes HTTP. La canalización de solicitudes se configura mediante la adición de componentes de middleware a una instancia de IApplicationBuilder. IApplicationBuilder está disponible para el método Configure, pero no está registrado en el contenedor de servicios. El hospedaje crea un elemento IApplicationBuilder y lo pasa directamente a Configure.

Las plantillas de ASP.NET Core configuran la canalización con compatibilidad para lo siguiente:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
    }

    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.UseAuthorization();

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

El ejemplo anterior corresponde a Razor Pages; la versión para MVC es similar.

Cada método de extensión Use agrega uno o más componentes de middleware a la canalización de solicitudes. Por ejemplo, UseStaticFiles configura UseStaticFiles para proporcionar archivos estáticos.

Cada componente de middleware de la canalización de solicitudes es responsable de invocar al siguiente componente de la canalización o de cortocircuitar la cadena en caso de ser necesario.

En la firma del método Configure se pueden especificar servicios adicionales, como IWebHostEnvironment, ILoggerFactory, o bien todo lo definido en ConfigureServices. Estos servicios adicionales se insertan si están disponibles.

Para más información sobre cómo usar IApplicationBuilder y el orden de procesamiento de middleware, vea IApplicationBuilder.

Configuración de servicios sin inicio

Para configurar los servicios y la canalización de procesamiento de solicitudes sin usar una clase Startup, llame a los métodos de conveniencia ConfigureServices y Configure en el generador de host. Varias llamadas a ConfigureServices se anexan entre sí. Si hay varias llamadas al método Configure, se usa la última llamada a Configure.

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.ConfigureServices(services =>
                {
                    services.AddControllersWithViews();
                })
                .Configure(app =>
                {
                    var loggerFactory = app.ApplicationServices
                        .GetRequiredService<ILoggerFactory>();
                    var logger = loggerFactory.CreateLogger<Program>();
                    var env = app.ApplicationServices.GetRequiredService<IWebHostEnvironment>();
                    var config = app.ApplicationServices.GetRequiredService<IConfiguration>();

                    logger.LogInformation("Logged in Configure");

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

                    var configValue = config["MyConfigKey"];
                });
            });
        });
}

Extensión del inicio con filtros de inicio

Use IStartupFilter:

  • Para configurar el middleware al principio o al final de la canalización de middleware Configure de una aplicación sin una llamada explícita a Use{Middleware}. ASP.NET Core usa IStartupFilter para agregar los valores predeterminados al principio de la canalización sin que el creador de la aplicación tenga que registrar explícitamente el middleware predeterminado. IStartupFilter permite que otro componente llame a Use{Middleware} en nombre del creador de la aplicación.
  • Para crear una canalización de métodos Configure. IStartupFilter.Configure puede configurar middleware para que se ejecute antes o después del middleware agregado por las bibliotecas.

IStartupFilter implementa Configure, que recibe y devuelve un elemento Action<IApplicationBuilder>. IApplicationBuilder define una clase para configurar la canalización de solicitudes de una aplicación. Para más información, vea Creación de una canalización de middleware con IApplicationBuilder.

Cada instancia de IStartupFilter puede agregar uno o más middleware en la canalización de solicitudes. Los filtros se invocan en el orden en que se agregaron al contenedor de servicios. Los filtros pueden agregar middleware antes o después de pasar el control al siguiente filtro, por lo que se anexan al principio o al final de la canalización de la aplicación.

En el ejemplo siguiente, se muestra cómo registrar un componente de middleware con IStartupFilter. El componente de middleware RequestSetOptionsMiddleware establece un valor de opciones de un parámetro de cadena de consulta:

public class RequestSetOptionsMiddleware
{
    private readonly RequestDelegate _next;

    public RequestSetOptionsMiddleware( RequestDelegate next )
    {
        _next = next;
    }

    // Test with https://localhost:5001/Privacy/?option=Hello
    public async Task Invoke(HttpContext httpContext)
    {
        var option = httpContext.Request.Query["option"];

        if (!string.IsNullOrWhiteSpace(option))
        {
            httpContext.Items["option"] = WebUtility.HtmlEncode(option);
        }

        await _next(httpContext);
    }
}

RequestSetOptionsMiddleware está configurado en las clase RequestSetOptionsStartupFilter:

public class RequestSetOptionsStartupFilter : IStartupFilter
{
    public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
    {
        return builder =>
        {
            builder.UseMiddleware<RequestSetOptionsMiddleware>();
            next(builder);
        };
    }
}

IStartupFilter se registra en el contenedor de servicios en ConfigureServices.

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
           .ConfigureAppConfiguration((hostingContext, config) =>
           {
           })
         .ConfigureWebHostDefaults(webBuilder =>
         {
             webBuilder.UseStartup<Startup>();
         })
        .ConfigureServices(services =>
        {
            services.AddTransient<IStartupFilter,
                      RequestSetOptionsStartupFilter>();
        });
}

Cuando se proporciona un parámetro de cadena de consulta para option, el middleware procesa la asignación del valor antes de que el middleware de ASP.NET Core represente la respuesta.

El orden de ejecución de middleware se establece según el orden de registros de IStartupFilter:

  • Varias implementaciones de IStartupFilter pueden interactuar con los mismos objetos. Si el orden es importante, ordene los registros de servicio de IStartupFilter para que coincidan con el orden en que se deben ejecutar los middleware.

  • Las bibliotecas pueden agregar middleware con una o varias implementaciones de IStartupFilter que se ejecuten antes o después de otro middleware de aplicación registrado con IStartupFilter. Para invocar un middleware IStartupFilter antes de un middleware agregado por el elemento IStartupFilter de una biblioteca:

    • Coloque el registro del servicio antes de que la biblioteca se agregue al contenedor de servicios.
    • Para la invocación posterior, coloque el registro del servicio después de que se agregue la biblioteca.

Agregar opciones de configuración en el inicio desde un ensamblado externo

Una implementación de IHostingStartup permite agregar mejoras a una aplicación al iniciarla a partir de un ensamblado externo fuera de la clase Startup de esta. Para obtener más información, consulte Uso de ensamblados de inicio de hospedaje en ASP.NET Core.

Recursos adicionales