Dela via


Migrera ASP.NET Framework HttpContext till ASP.NET Core

HttpContext är en grundläggande komponent i webbprogram som ger åtkomst till HTTP-begäran och svarsinformation. När du migrerar från ASP.NET Framework till ASP.NET Core innebär HttpContext unika utmaningar eftersom de två ramverken har olika API:er och metoder.

Varför HttpContext-migrering är komplex

ASP.NET Framework och ASP.NET Core har fundamentalt olika HttpContext-implementeringar:

Dessa skillnader innebär att du inte bara kan flytta din HttpContext-kod från Framework till Core utan ändringar.

Översikt över migreringsstrategier

Du har två huvudsakliga metoder för att hantera HttpContext under migreringen:

  1. Fullständig omskrivning – Skriv om all HttpContext-kod för att använda ASP.NET Cores interna HttpContext-implementering
  2. System.Web-adaptrar – Använd adaptrar för att minimera kodändringar vid migrering stegvis

För de flesta program ger migrering till ASP.NET Cores interna HttpContext bästa prestanda och underhållsbarhet. Större program eller program med omfattande HttpContext-användning kan dock ha nytta av att använda System.Web-kort under inkrementell migrering.

Välj migreringsmetod

Du har två huvudsakliga alternativ för att migrera HttpContext från ASP.NET Framework till ASP.NET Core. Ditt val beror på din tidslinje för migrering, om du behöver köra båda programmen samtidigt och hur mycket kod du är villig att skriva om.

Snabb beslutsguide

Besvara dessa frågor för att välja din metod:

  1. Gör du en fullständig omskrivning eller inkrementell migrering?

  2. Har du omfattande HttpContext-användning i delade bibliotek?

Jämförelse av migreringstillvägagångssätt

Tillvägagångssätt Kodändringar Prestanda Delade bibliotek När du ska använda
Fullständig omskrivning Hög – Skriv om all HttpContext-kod Bäst Kräver uppdateringar Slutför omskrivningar, prestandakritiska appar
System.Web-adaptrar Låg – Behåll befintliga mönster Bra Fungerar med befintlig kod Inkrementella migreringar, omfattande HttpContext-användning

Viktiga skillnader

HttpContext-livslängd

Adaptrarna stöds av HttpContext som inte kan användas efter livet av en begäran. HttpContext När den körs på ASP.NET Core kan därför inte även användas efter en begäran, medan den i ASP.NET Framework skulle fungera ibland. En ObjectDisposedException utlöses i de fall där den används efter att en begäran har avslutats.

Rekommendation: Lagra de värden som behövs i en POCO och håll fast vid det.

Be om trådöverväganden

Varning

ASP.NET Core garanterar inte trådtillhörighet för begäranden. Om koden kräver trådsäker åtkomst till HttpContextmåste du säkerställa korrekt synkronisering.

I ASP.NET Framework hade en begäran trådtillhörighet och Current skulle endast vara tillgänglig om den finns i den tråden. ASP.NET Core har inte den här garantin så Current kommer att vara tillgänglig inom samma asynkrona kontext, men inga garantier för trådar görs.

Rekommendation: Om du läser/skriver till HttpContext måste du se till att du gör det på ett enskilt trådat sätt. Du kan tvinga en begäran att aldrig köras samtidigt i någon asynkron kontext genom att ange ISingleThreadedRequestMetadata. Detta får prestandakonsekvenser och bör endast användas om du inte kan omstrukturera användningen för att säkerställa icke-samtidig åtkomst. Det finns en implementering tillgänglig att lägga till för styrenheter med SingleThreadedRequestAttribute:

[SingleThreadedRequest]
public class SomeController : Controller
{
    ...
} 

Begär strömbuffertning

Som standard är den inkommande begäran inte alltid sökbar eller helt tillgänglig. För att uppnå det beteende som finns i .NET Framework kan du välja att förbuffra indataströmmen. Detta läser den inkommande strömmen fullständigt och buffras till minne eller disk (beroende på inställningar).

Rekommendation: Detta kan aktiveras genom att använda slutpunktsmetadata som implementerar IPreBufferRequestStreamMetadata gränssnittet. Detta är tillgängligt som ett attribut PreBufferRequestStreamAttribute som kan tillämpas på kontrollanter eller metoder.

För att aktivera detta på alla MVC-slutpunkter finns det en tilläggsmetod som kan användas på följande sätt:

app.MapDefaultControllerRoute()
    .PreBufferRequestStream();

Buffring av svarsström

Vissa API:er på Response kräver att utdataströmmen buffrats, till exempel Output, End(), Clear()och SuppressContent.

Rekommendation: För att stöda beteende för Response detta kräver buffring av svaret innan det skickas, måste slutpunkter välja det med slutpunktsmetadata som implementerar IBufferResponseStreamMetadata.

För att aktivera detta på alla MVC-slutpunkter finns det en tilläggsmetod som kan användas på följande sätt:

app.MapDefaultControllerRoute()
    .BufferResponseStream();

Slutför omskrivningen till ASP.NET Core HttpContext

Välj den här metoden när du utför en fullständig migrering och kan skriva om HttpContext-relaterad kod för att använda ASP.NET Cores interna implementering.

ASP.NET Cores HttpContext ger en mer modulär och utökningsbar design jämfört med ASP.NET Framework. Den här metoden ger bästa prestanda men kräver fler kodändringar under migreringen.

Översikt

HttpContext har ändrats avsevärt i ASP.NET Core. När du migrerar HTTP-moduler eller hanterare till mellanprogram måste du uppdatera koden så att den fungerar med det nya HttpContext API:et.

I ASP.NET Core-mellanprogram Invoke tar metoden en parameter av typen HttpContext:

public async Task Invoke(HttpContext context)

Detta HttpContext skiljer sig från ASP.NET Framework-versionen och kräver olika metoder för åtkomst till information om begäranden och svar.

Egenskapsöversättningar

Det här avsnittet visar hur du översätter de vanligaste egenskaperna System.Web.HttpContext för till motsvarande Microsoft.AspNetCore.Http.HttpContext i ASP.NET Core.

HttpContext-egenskaper

HttpRequest-egenskaper

  • HttpRequest.HttpMethodHttpRequest.Method

    string httpMethod = httpContext.Request.Method;
    
  • HttpRequest.QueryStringHttpRequest.QueryString

    IQueryCollection queryParameters = httpContext.Request.Query;
    
    // If no query parameter "key" used, values will have 0 items
    // If single value used for a key (...?key=v1), values will have 1 item ("v1")
    // If key has multiple values (...?key=v1&key=v2), values will have 2 items ("v1" and "v2")
    IList<string> values = queryParameters["key"];
    
    // If no query parameter "key" used, value will be ""
    // If single value used for a key (...?key=v1), value will be "v1"
    // If key has multiple values (...?key=v1&key=v2), value will be "v1,v2"
    string value = queryParameters["key"].ToString();
    
  • HttpRequest.Url / HttpRequest.RawUrlFlera egenskaper

    // using Microsoft.AspNetCore.Http.Extensions;
    var url = httpContext.Request.GetDisplayUrl();
    

    Använd Request.Scheme, Host, PathBase, Path, QueryString

  • HttpRequest.IsSecureConnectionHttpRequest.IsHttps

    var isSecureConnection = httpContext.Request.IsHttps;
    
  • HttpRequest.UserHostAddressConnectionInfo.RemoteIpAddress

    var userHostAddress = httpContext.Connection.RemoteIpAddress?.ToString();
    
  • HttpRequest.CookiesHttpRequest.Cookies

    IRequestCookieCollection cookies = httpContext.Request.Cookies;
    string unknownCookieValue = cookies["unknownCookie"]; // will be null (no exception)
    string knownCookieValue = cookies["cookie1name"];     // will be actual value
    
  • HttpRequest.RequestContextRoutingHttpContextExtensions.GetRouteData

    var routeValue = httpContext.GetRouteValue("key");
    
  • HttpRequest.HeadersHttpRequest.Headers

    // using Microsoft.AspNetCore.Http.Headers;
    // using Microsoft.Net.Http.Headers;
    
    IHeaderDictionary headersDictionary = httpContext.Request.Headers;
    
    // GetTypedHeaders extension method provides strongly typed access to many headers
    var requestHeaders = httpContext.Request.GetTypedHeaders();
    CacheControlHeaderValue cacheControlHeaderValue = requestHeaders.CacheControl;
    
    // For unknown header, unknownheaderValues has zero items and unknownheaderValue is ""
    IList<string> unknownheaderValues = headersDictionary["unknownheader"];
    string unknownheaderValue = headersDictionary["unknownheader"].ToString();
    
    // For known header, knownheaderValues has 1 item and knownheaderValue is the value
    IList<string> knownheaderValues = headersDictionary[HeaderNames.AcceptLanguage];
    string knownheaderValue = headersDictionary[HeaderNames.AcceptLanguage].ToString();
    
  • HttpRequest.UserAgentHttpRequest.Headers

    string userAgent = headersDictionary[HeaderNames.UserAgent].ToString();
    
  • HttpRequest.UrlReferrerHttpRequest.Headers

    string urlReferrer = headersDictionary[HeaderNames.Referer].ToString();
    
  • HttpRequest.ContentTypeHttpRequest.ContentType

    // using Microsoft.Net.Http.Headers;
    
    MediaTypeHeaderValue mediaHeaderValue = requestHeaders.ContentType;
    string contentType = mediaHeaderValue?.MediaType.ToString();   // ex. application/x-www-form-urlencoded
    string contentMainType = mediaHeaderValue?.Type.ToString();    // ex. application
    string contentSubType = mediaHeaderValue?.SubType.ToString();  // ex. x-www-form-urlencoded
    
    System.Text.Encoding requestEncoding = mediaHeaderValue?.Encoding;
    
  • HttpRequest.FormHttpRequest.Form

    if (httpContext.Request.HasFormContentType)
    {
        IFormCollection form;
    
        form = httpContext.Request.Form; // sync
        // Or
        form = await httpContext.Request.ReadFormAsync(); // async
    
        string firstName = form["firstname"];
        string lastName = form["lastname"];
    }
    

    Varning: Läs formulärvärden endast om innehållstypen är x-www-form-urlencoded eller form-data

  • HttpRequest.InputStreamHttpRequest.Body

    string inputBody;
    using (var reader = new System.IO.StreamReader(
        httpContext.Request.Body, System.Text.Encoding.UTF8))
    {
        inputBody = reader.ReadToEnd();
    }
    

    Varning: Använd endast i mellanprogram för hanterare i slutet av pipelinen. Body kan bara läsas en gång per anrop

HttpResponse-egenskaper

  • HttpResponse.Status / HttpResponse.StatusDescriptionHttpResponse.StatusCode

    // using Microsoft.AspNetCore.Http;
    httpContext.Response.StatusCode = StatusCodes.Status200OK;
    
  • HttpResponse.ContentEncoding / HttpResponse.ContentTypeHttpResponse.ContentType

    // using Microsoft.Net.Http.Headers;
    var mediaType = new MediaTypeHeaderValue("application/json");
    mediaType.Encoding = System.Text.Encoding.UTF8;
    httpContext.Response.ContentType = mediaType.ToString();
    
  • HttpResponse.ContentTypeHttpResponse.ContentType

    httpContext.Response.ContentType = "text/html";
    
  • HttpResponse.OutputHttpResponseWritingExtensions.WriteAsync

    string responseContent = GetResponseContent();
    await httpContext.Response.WriteAsync(responseContent);
    
  • HttpResponse.TransmitFileSe förfrågningsfunktioner

    Serveringsfiler beskrivs i begärandefunktioner i ASP.NET Core

  • HttpResponse.HeadersHttpResponse.OnStarting

    // using Microsoft.AspNet.Http.Headers;
    // using Microsoft.Net.Http.Headers;
    
    private Task SetHeaders(object context)
    {
        var httpContext = (HttpContext)context;
    
        // Set header with single value
        httpContext.Response.Headers["ResponseHeaderName"] = "headerValue";
    
        // Set header with multiple values
        string[] responseHeaderValues = new string[] { "headerValue1", "headerValue1" };
        httpContext.Response.Headers["ResponseHeaderName"] = responseHeaderValues;
    
        // Translating ASP.NET 4's HttpContext.Response.RedirectLocation  
        httpContext.Response.Headers[HeaderNames.Location] = "http://www.example.com";
        // Or
        httpContext.Response.Redirect("http://www.example.com");
    
        // GetTypedHeaders extension method provides strongly typed access to many headers
        var responseHeaders = httpContext.Response.GetTypedHeaders();
    
        // Translating ASP.NET 4's HttpContext.Response.CacheControl 
        responseHeaders.CacheControl = new CacheControlHeaderValue
        {
            MaxAge = new System.TimeSpan(365, 0, 0, 0)
            // Many more properties available 
        };
    
        // If you use .NET Framework 4.6+, Task.CompletedTask will be a bit faster
        return Task.FromResult(0);
    }
    

    Måste använda callback-mönster för att ange huvuden innan svaret startar

  • HttpResponse.CookiesHttpResponse.OnStarting

    private Task SetCookies(object context)
    {
        var httpContext = (HttpContext)context;
    
        IResponseCookies responseCookies = httpContext.Response.Cookies;
    
        responseCookies.Append("cookie1name", "cookie1value");
        responseCookies.Append("cookie2name", "cookie2value",
            new CookieOptions { Expires = System.DateTime.Now.AddDays(5), HttpOnly = true });
    
        // If you use .NET Framework 4.6+, Task.CompletedTask will be a bit faster
        return Task.FromResult(0); 
    }
    

    Måste använda återanropsmönster för att ange cookies innan svaret startar

  • Ange svarshuvuden:

    public async Task Invoke(HttpContext httpContext)
    {
        // Set callback to execute before response starts
        httpContext.Response.OnStarting(SetHeaders, state: httpContext);
        // ... rest of middleware logic
    }
    
  • Ange svarscookies:

public async Task Invoke(HttpContext httpContext)
{
    // Set callbacks to execute before response starts
    httpContext.Response.OnStarting(SetCookies, state: httpContext);
    httpContext.Response.OnStarting(SetHeaders, state: httpContext);
    // ... rest of middleware logic
}

System.Web-adaptrar

Anmärkning

På så sätt används System.Web Adapters för att förenkla migreringen.

Välj den här metoden när du har omfattande HttpContext-användning i delade bibliotek eller när du utför en inkrementell migrering där du vill minimera kodändringar.

System.Web-adaptrar tillhandahåller ett kompatibilitetslager som gör att du kan använda bekanta HttpContext API:er i ASP.NET Core-program. Den här metoden är särskilt användbar när:

  • Du har gemensamma bibliotek som använder HttpContext
  • Du utför en inkrementell migrering
  • Du vill minimera kodändringar under migreringsprocessen

Fördelar med att använda System.Web-adaptrar

  • Minimala kodändringar: Behåll dina befintliga System.Web.HttpContext användningsmönster
  • Delade bibliotek: Bibliotek kan fungera med både ASP.NET Framework och ASP.NET Core
  • Inkrementell migrering: Migrera program bit för bit utan att bryta delade beroenden
  • Snabbare migrering: Minska den tid som krävs för att migrera komplexa program

Överväganden

  • Prestanda: Även om de är bra medför adaptrar viss overhead jämfört med inbyggda ASP.NET Core-API:er
  • Funktionsparitet: Inte alla funktioner är tillgängliga via HttpContext adaptrar
  • Långsiktig strategi: Överväg att så småningom migrera till interna ASP.NET Core-API:er för bästa prestanda

Mer information om System.Web-kort finns i dokumentationen om System.Web-kort.

Ytterligare resurser