Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Den här artikeln visar hur du migrerar befintliga ASP.NET HTTP-moduler från system.webserver till ASP.NET Core-mellanprogram.
Modulerna har återbesökts
Innan vi fortsätter till ASP.NET Core-mellanprogram ska vi först sammanfatta hur HTTP-moduler fungerar:
               
              
            
Moduler är:
- Klasser som implementerar IHttpModule 
- Anropas för varje begäran 
- Det går att avbryta vidare bearbetning av en begäran. 
- Kan lägga till i HTTP-svaret eller skapa egna 
- Konfigurerad i Web.config 
I vilken ordning moduler bearbetar inkommande begäranden bestäms av:
- En seriehändelser som utlöses av ASP.NET, till exempel BeginRequest och AuthenticateRequest. En fullständig lista finns i System.Web.HttpApplication. Varje modul kan skapa en hanterare för en eller flera händelser. 
- För samma händelse är den ordning i vilken de konfigureras i Web.config. 
Förutom moduler kan du lägga till hanterare för livscykelhändelserna i filen Global.asax.cs . Dessa hanterare körs efter hanterarna i de konfigurerade modulerna.
Från moduler till mellanprogram
Mellanprogram är enklare än HTTP-moduler:
- Moduler, - Global.asax.cs, Web.config (förutom IIS-konfiguration) och programmets livscykel är borta
- Rollerna för moduler har tagits över av mellanprogram 
- Mellanprogram konfigureras med hjälp av kod snarare än i Web.config 
- Med pipelineförgrening kan du skicka begäranden till specifika mellanprogram, baserat på inte bara URL:en utan även på begärandehuvuden, frågesträngar osv.
- Med pipelineförgrening kan du skicka begäranden till specifika mellanprogram, baserat på inte bara URL:en utan även på begärandehuvuden, frågesträngar osv.
Mellanprogram är mycket lika moduler:
- Anropas i princip för varje begäran 
- Det går att kortsluta en begäran genom att inte skicka begäran till nästa mellanprogram 
- Kunna skapa ett eget HTTP-svar 
Mellanprogram och moduler bearbetas i en annan ordning:
- Ordningen på mellanprogram baseras på i vilken ordning de infogas i begärandepipelinen, medan ordningen på moduler huvudsakligen baseras på System.Web.HttpApplication händelser. 
- Ordningen på mellanprogram för svar är omvänd från den för begäranden, medan ordningen på moduler är densamma för begäranden och svar 
- Se Skapa en pipeline för mellanprogram med IApplicationBuilder 
               
              
            
Observera hur i bilden ovan kortsluter autentiseringsmellanprogrammet begäran.
Migrera modulkod till mellanprogram
En befintlig HTTP-modul ser ut ungefär så här:
// ASP.NET 4 module
using System;
using System.Web;
namespace MyApp.Modules
{
    public class MyModule : IHttpModule
    {
        public void Dispose()
        {
        }
        public void Init(HttpApplication application)
        {
            application.BeginRequest += (new EventHandler(this.Application_BeginRequest));
            application.EndRequest += (new EventHandler(this.Application_EndRequest));
        }
        private void Application_BeginRequest(Object source, EventArgs e)
        {
            HttpContext context = ((HttpApplication)source).Context;
            // Do something with context near the beginning of request processing.
        }
        private void Application_EndRequest(Object source, EventArgs e)
        {
            HttpContext context = ((HttpApplication)source).Context;
            // Do something with context near the end of request processing.
        }
    }
}
Som du ser på sidan Mellanprogram är ett ASP.NET Core-mellanprogram en klass som exponerar en Invoke metod som tar en HttpContext och returnerar en Task. Ditt nya mellanprogram ser ut så här:
// ASP.NET Core middleware
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
namespace MyApp.Middleware
{
    public class MyMiddleware
    {
        private readonly RequestDelegate _next;
        public MyMiddleware(RequestDelegate next)
        {
            _next = next;
        }
        public async Task Invoke(HttpContext context)
        {
            // Do something with context near the beginning of request processing.
            await _next.Invoke(context);
            // Clean up.
        }
    }
    public static class MyMiddlewareExtensions
    {
        public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<MyMiddleware>();
        }
    }
}
Föregående mall för mellanprogram togs från avsnittet om att skriva mellanprogram.
              Hjälpklassen MyMiddlewareExtensions gör det enklare att konfigurera mellanprogrammet i klassenStartup. Metoden UseMyMiddleware lägger till din mellanprogramsklass i begärandepipelinen. Tjänster som krävs av mellanprogrammet matas in i mellanprogrammets konstruktor.
Modulen kan avsluta en begäran, till exempel om användaren inte har behörighet:
// ASP.NET 4 module that may terminate the request
private void Application_BeginRequest(Object source, EventArgs e)
{
    HttpContext context = ((HttpApplication)source).Context;
    // Do something with context near the beginning of request processing.
    if (TerminateRequest())
    {
        context.Response.End();
        return;
    }
}
Ett mellanprogram hanterar detta genom att inte anropa Invoke nästa mellanprogram i pipelinen. Tänk på att detta inte helt avslutar begäran, eftersom tidigare mellanprogram fortfarande anropas när svaret tar sig tillbaka genom pipelinen.
// ASP.NET Core middleware that may terminate the request
public async Task Invoke(HttpContext context)
{
    // Do something with context near the beginning of request processing.
    if (!TerminateRequest())
        await _next.Invoke(context);
    // Clean up.
}
När du migrerar modulens funktioner till ditt nya mellanprogram kan det hända att koden inte kompileras eftersom HttpContext klassen har ändrats avsevärt i ASP.NET Core. Se Migrera från ASP.NET Framework HttpContext till ASP.NET Core för att lära dig hur du migrerar till den nya ASP.NET Core HttpContext.
Migrera modulinfogning till pipelinen för begäran
HTTP-moduler läggs vanligtvis till i begärans pipeline med Web.config:
<?xml version="1.0" encoding="utf-8"?>
<!--ASP.NET 4 web.config-->
<configuration>
  <system.webServer>
    <modules>
      <add name="MyModule" type="MyApp.Modules.MyModule"/>
    </modules>
  </system.webServer>
</configuration>
Konvertera detta genom att lägga till ditt nya mellanprogram i pipelinen för begäran i klassen Startup :
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseBrowserLink();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }
    app.UseMyMiddleware();
    app.UseMyMiddlewareWithParams();
    var myMiddlewareOptions = Configuration.GetSection("MyMiddlewareOptionsSection").Get<MyMiddlewareOptions>();
    var myMiddlewareOptions2 = Configuration.GetSection("MyMiddlewareOptionsSection2").Get<MyMiddlewareOptions>();
    app.UseMyMiddlewareWithParams(myMiddlewareOptions);
    app.UseMyMiddlewareWithParams(myMiddlewareOptions2);
    app.UseMyTerminatingMiddleware();
    // Create branch to the MyHandlerMiddleware. 
    // All requests ending in .report will follow this branch.
    app.MapWhen(
        context => context.Request.Path.ToString().EndsWith(".report"),
        appBranch => {
            // ... optionally add more middleware to this branch
            appBranch.UseMyHandler();
        });
    app.MapWhen(
        context => context.Request.Path.ToString().EndsWith(".context"),
        appBranch => {
            appBranch.UseHttpContextDemoMiddleware();
        });
    app.UseStaticFiles();
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}
Den exakta platsen i pipelinen där du infogar ditt nya mellanprogram beror på vilken händelse det hanterade som en modul (BeginRequest, EndRequestosv.) och dess ordning i listan över moduler i Web.config.
Som tidigare nämnts finns det ingen programlivscykel i ASP.NET Core och i vilken ordning svar bearbetas av mellanprogram skiljer sig från den ordning som används av moduler. Detta kan göra beställningsbeslutet mer utmanande.
Om beställningen blir ett problem kan du dela upp modulen i flera mellanprogramskomponenter som kan beställas separat.
Ladda middleware-alternativ med hjälp av alternativmönstret
Vissa moduler har konfigurationsalternativ som lagras i Web.config. I ASP.NET Core används dock en ny konfigurationsmodell i stället förWeb.config.
Det nya konfigurationssystemet ger dig följande alternativ för att lösa detta:
- Mata in alternativen direkt i mellanprogrammet, som du ser i nästa avsnitt. 
- Använd alternativmönstret: 
- Skapa en klass som innehåller mellanprogramsalternativen, till exempel: - public class MyMiddlewareOptions { public string Param1 { get; set; } public string Param2 { get; set; } }
- Lagra alternativvärdena - Med konfigurationssystemet kan du lagra alternativvärden var du vill. De flesta webbplatser använder - appsettings.jsondock , så vi använder den metoden:- { "MyMiddlewareOptionsSection": { "Param1": "Param1Value", "Param2": "Param2Value" } }- MyMiddlewareOptionsSection här är ett avsnittsnamn. Det behöver inte vara samma som namnet på din alternativklass. 
- Associera alternativvärdena med alternativklassen - Alternativmönstret använder ASP.NET Cores beroendeinmatningsramverk för att associera alternativtypen (till exempel - MyMiddlewareOptions) med ett- MyMiddlewareOptionsobjekt som har de faktiska alternativen.- Uppdatera klassen - Startup:- Om du använder - appsettings.json, lägg till det i konfigurationsbyggaren i konstruktorn- Startup.- public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) .AddEnvironmentVariables(); Configuration = builder.Build(); }
- Konfigurera alternativtjänsten: - public void ConfigureServices(IServiceCollection services) { // Setup options service services.AddOptions(); // Load options from section "MyMiddlewareOptionsSection" services.Configure<MyMiddlewareOptions>( Configuration.GetSection("MyMiddlewareOptionsSection")); // Add framework services. services.AddMvc(); }
- Associera dina alternativ med din alternativklass: - public void ConfigureServices(IServiceCollection services) { // Setup options service services.AddOptions(); // Load options from section "MyMiddlewareOptionsSection" services.Configure<MyMiddlewareOptions>( Configuration.GetSection("MyMiddlewareOptionsSection")); // Add framework services. services.AddMvc(); }
 
- Mata in alternativen i mellanprogramskonstruktorn. Detta liknar inmatningsalternativ i en styrenhet. - public class MyMiddlewareWithParams { private readonly RequestDelegate _next; private readonly MyMiddlewareOptions _myMiddlewareOptions; public MyMiddlewareWithParams(RequestDelegate next, IOptions<MyMiddlewareOptions> optionsAccessor) { _next = next; _myMiddlewareOptions = optionsAccessor.Value; } public async Task Invoke(HttpContext context) { // Do something with context near the beginning of request processing // using configuration in _myMiddlewareOptions await _next.Invoke(context); // Do something with context near the end of request processing // using configuration in _myMiddlewareOptions } }- UseMiddleware-tilläggsmetoden som lägger till ditt mellanprogram i - IApplicationBuildertar hand om beroendeinjektionen.- Detta är inte begränsat till - IOptionsobjekt. Alla andra objekt som ditt mellanprogram kräver kan matas in på det här sättet.
Läsa in mellanprogramsalternativ via direktinmatning
Alternativmönstret har fördelen att det skapar lös koppling mellan alternativvärden och deras konsumenter. När du har associerat en alternativklass med de faktiska alternativvärdena kan alla andra klasser få åtkomst till alternativen via beroendeinmatningsramverket. Du behöver inte skicka runt alternativvärden.
Detta delas dock upp om du vill använda samma mellanprogram två gånger, med olika alternativ. Till exempel ett mellanprogram för auktorisering som används i olika grenar som tillåter olika roller. Du kan inte associera två olika alternativobjekt med klassen one options.
Lösningen är att hämta alternativobjekten med de faktiska alternativvärdena i klassen Startup och skicka dem direkt till varje instans av mellanprogrammet.
- Lägg till en andra nyckel i - appsettings.json- Om du vill lägga till en andra uppsättning alternativ i - appsettings.jsonfilen använder du en ny nyckel för att unikt identifiera den:- { "MyMiddlewareOptionsSection2": { "Param1": "Param1Value2", "Param2": "Param2Value2" }, "MyMiddlewareOptionsSection": { "Param1": "Param1Value", "Param2": "Param2Value" } }
- Hämta alternativvärden och skicka dem till mellanprogram. Tilläggsmetoden - Use...(som lägger till mellanprogrammet i pipelinen) är en logisk plats för att skicka in alternativvärdena:- public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseBrowserLink(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseMyMiddleware(); app.UseMyMiddlewareWithParams(); var myMiddlewareOptions = Configuration.GetSection("MyMiddlewareOptionsSection").Get<MyMiddlewareOptions>(); var myMiddlewareOptions2 = Configuration.GetSection("MyMiddlewareOptionsSection2").Get<MyMiddlewareOptions>(); app.UseMyMiddlewareWithParams(myMiddlewareOptions); app.UseMyMiddlewareWithParams(myMiddlewareOptions2); app.UseMyTerminatingMiddleware(); // Create branch to the MyHandlerMiddleware. // All requests ending in .report will follow this branch. app.MapWhen( context => context.Request.Path.ToString().EndsWith(".report"), appBranch => { // ... optionally add more middleware to this branch appBranch.UseMyHandler(); }); app.MapWhen( context => context.Request.Path.ToString().EndsWith(".context"), appBranch => { appBranch.UseHttpContextDemoMiddleware(); }); app.UseStaticFiles(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); }
- Aktivera mellanprogram för att ta en alternativparameter. Tillhandahåll en överlagring av - Use...-tilläggsmetoden (som tar alternativparametern och skickar den till- UseMiddleware). När- UseMiddlewareanropas med parametrar skickas parametrarna till mellanprogramskonstruktorn när det instansierar mellanprogramsobjektet.- public static class MyMiddlewareWithParamsExtensions { public static IApplicationBuilder UseMyMiddlewareWithParams( this IApplicationBuilder builder) { return builder.UseMiddleware<MyMiddlewareWithParams>(); } public static IApplicationBuilder UseMyMiddlewareWithParams( this IApplicationBuilder builder, MyMiddlewareOptions myMiddlewareOptions) { return builder.UseMiddleware<MyMiddlewareWithParams>( new OptionsWrapper<MyMiddlewareOptions>(myMiddlewareOptions)); } }- Observera hur detta omsluter alternativobjektet i ett - OptionsWrapperobjekt. Detta implementerar- IOptions, som förväntat av mellanprogramskonstruktorn.
Inkrementell IHttpModule-migrering
Det finns tillfällen då det inte är enkelt att konvertera moduler till mellanprogram. För att stödja migreringsscenarier i vilka moduler krävs och inte kan flyttas till mellanlager, har System.Web-adaptrar stöd för att lägga till dem i ASP.NET Core.
IHttpModule-exempel
För att kunna stödja moduler måste en instans av HttpApplication vara tillgänglig. Om ingen anpassad HttpApplication används kommer en standardinställning att användas för att lägga till modulerna i. Händelser som deklareras i ett anpassat program (inklusive Application_Start) registreras och körs därefter.
using System.Web;
using Microsoft.AspNetCore.OutputCaching;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSystemWebAdapters()
    .AddHttpApplication<MyApp>(options =>
    {
        // Size of pool for HttpApplication instances. Should be what the expected concurrent requests will be
        options.PoolSize = 10;
        // Register a module (optionally) by name
        options.RegisterModule<MyModule>("MyModule");
    });
// Only available in .NET 7+
builder.Services.AddOutputCache(options =>
{
    options.AddHttpApplicationBasePolicy(_ => new[] { "browser" });
});
builder.Services.AddAuthentication();
builder.Services.AddAuthorization();
var app = builder.Build();
app.UseAuthentication();
app.UseAuthenticationEvents();
app.UseAuthorization();
app.UseAuthorizationEvents();
app.UseSystemWebAdapters();
app.UseOutputCache();
app.MapGet("/", () => "Hello World!")
    .CacheOutput();
app.Run();
class MyApp : HttpApplication
{
    protected void Application_Start()
    {
    }
    public override string? GetVaryByCustomString(System.Web.HttpContext context, string custom)
    {
        // Any custom vary-by string needed
        return base.GetVaryByCustomString(context, custom);
    }
}
class MyModule : IHttpModule
{
    public void Init(HttpApplication application)
    {
        application.BeginRequest += (s, e) =>
        {
            // Handle events at the beginning of a request
        };
        application.AuthorizeRequest += (s, e) =>
        {
            // Handle events that need to be authorized
        };
    }
    public void Dispose()
    {
    }
}
Global.asax-migrering
Den här infrastrukturen kan användas för att migrera användningen av Global.asax vid behov. Källan från Global.asax är anpassad HttpApplication och filen kan ingå i ett ASP.NET Core-program. Eftersom den heter Globalkan följande kod användas för att registrera den:
builder.Services.AddSystemWebAdapters()
    .AddHttpApplication<Global>();
Så länge logiken i den är tillgänglig i ASP.NET Core kan den här metoden användas för att stegvis migrera beroendet av Global.asax till ASP.NET Core.
Autentiserings-/auktoriseringshändelser
För att autentiserings- och auktoriseringshändelserna ska kunna köras vid önskad tidpunkt bör följande mönster användas:
app.UseAuthentication();
app.UseAuthenticationEvents();
app.UseAuthorization();
app.UseAuthorizationEvents();
Om detta inte görs körs händelserna fortfarande. Det kommer dock att ske under anropet av .UseSystemWebAdapters().
HTTP-modulpool
Eftersom moduler och program i ASP.NET Framework har tilldelats en begäran behövs en ny instans för varje begäran. Men eftersom de kan vara dyra att skapa, sammanförs de med hjälp av ObjectPool<T>. För att anpassa den faktiska livslängden för HttpApplication instanserna kan en anpassad pool användas:
builder.Services.TryAddSingleton<ObjectPool<HttpApplication>>(sp =>
{
    // Recommended to use the in-built policy as that will ensure everything is initialized correctly and is not intended to be replaced
    var policy = sp.GetRequiredService<IPooledObjectPolicy<HttpApplication>>();
    // Can use any provider needed
    var provider = new DefaultObjectPoolProvider();
    // Use the provider to create a custom pool that will then be used for the application.
    return provider.Create(policy);
});
Ytterligare resurser
ASP.NET Core