Freigeben über


Migrieren von ASP.NET Framework HttpContext zu ASP.NET Core

HttpContext ist eine grundlegende Komponente von Webanwendungen, die Zugriff auf HTTP-Anforderungs- und Antwortinformationen bereitstellt. Bei der Migration von ASP.NET Framework zu ASP.NET Core stellt HttpContext einzigartige Herausforderungen dar, da die beiden Frameworks unterschiedliche APIs und Ansätze aufweisen.

Warum die HttpContext-Migration komplex ist

ASP.NET Framework und ASP.NET Core haben grundsätzlich unterschiedliche HttpContext-Implementierungen:

Diese Unterschiede bedeuten, dass Sie Ihren HttpContext-Code nicht einfach von Framework zu Core verschieben können, ohne Änderungen vorzunehmen.

Übersicht über Migrationsstrategien

Sie haben zwei Hauptansätze für die Behandlung von HttpContext während der Migration:

  1. Vollständige Neuschreibung - Schreiben Sie den gesamten HttpContext-Code neu, um die native HttpContext-Implementierung von ASP.NET Core zu verwenden.
  2. System.Webadapter – Verwenden von Adaptern zum Minimieren von Codeänderungen während der inkrementellen Migration

Für die meisten Anwendungen bietet die Migration zu ASP.NET Cores systemeigenem HttpContext die beste Leistung und Wartung. Größere Anwendungen oder solche mit umfangreicher HttpContext-Verwendung können jedoch von der Verwendung von System.Web-Adaptern während der inkrementellen Migration profitieren.

Auswählen Ihres Migrationsansatzes

Sie haben zwei Hauptoptionen für die Migration von HttpContext von ASP.NET Framework zu ASP.NET Core. Ihre Wahl hängt von Der Migrationszeitachse ab, ob Sie beide Anwendungen gleichzeitig ausführen müssen und wie viel Code Sie neu schreiben möchten.

Schnellentscheidungsleitfaden

Beantworten Sie diese Fragen, um Ihren Ansatz auszuwählen:

  1. Führen Sie eine vollständige Neuschreibung oder inkrementelle Migration durch?

  2. Haben Sie eine umfangreiche HttpContext-Nutzung für gemeinsame Bibliotheken?

Vergleich der Migrationsansätze

Vorgehensweise Codeänderungen Leistung Gemeinsame Bibliotheken Verwendung
Vollständige Neuschreibung Hoch - Alle HttpContext-Code neu schreiben Sehr hoch Erfordert Aktualisierungen Vollständige Neuschreibungen, leistungskritische Apps
System.Web Adapter Niedrig - Vorhandene Muster beibehalten Gut Funktioniert mit vorhandenem Code Inkrementelle Migrationen, umfangreiche HttpContext-Verwendung

Wichtige Unterschiede

HttpContext-Lebensdauer

Die Adapter werden von HttpContext gesichert, die über die Lebensdauer einer Anforderung hinaus nicht verwendet werden können. Wenn HttpContext unter ASP.NET Core ausgeführt wird, kann es nicht über eine einzelne Anfrage hinaus verwendet werden, während es im ASP.NET Framework manchmal funktioniert. Ein ObjectDisposedException wird in Fällen ausgelöst, in denen es über das Ende einer Anfrage hinaus verwendet wird.

Empfehlung: Speichern Sie die benötigten Werte in einem POCO und bewahren Sie diese auf.

Überlegungen zum Threading in Anfragen

Warnung

ASP.NET Core garantiert keine Threadaffinität für Anforderungen. Wenn Ihr Code threadsicheren Zugriff auf HttpContext erfordert, müssen Sie die ordnungsgemäße Synchronisierung sicherstellen.

In ASP.NET Framework hatte eine Anforderung Threadaffinität und Current wäre nur in diesem Thread verfügbar. ASP.NET Core bietet keine solche Garantie, daher ist Current innerhalb desselben asynchronen Kontexts verfügbar, aber es werden keine Garantien für Threads gegeben.

Empfehlung: Wenn Sie auf HttpContext lesen/schreiben, müssen Sie sicherstellen, dass Sie dies auf eine einzelthreadige Weise tun. Sie können erzwingen, dass eine Anforderung nie gleichzeitig in einem asynchronen Kontext ausgeführt wird, indem Sie die Einstellung festlegen ISingleThreadedRequestMetadata. Dies hat Leistungsauswirkungen und sollte nur verwendet werden, wenn Sie die Verwendung nicht umgestalten können, um den nicht gleichzeitigen Zugriff sicherzustellen. Es steht eine Implementierung zur Verfügung, die den Controllern hinzugefügt werden kann:SingleThreadedRequestAttribute

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

Anfordern der Stream-Pufferung

Standardmäßig ist die eingehende Anforderung nicht immer suchbar oder vollständig verfügbar. Um das im .NET Framework beobachtete Verhalten zu erzielen, haben Sie die Möglichkeit, den Eingabestrom zu vorpuffern. Dadurch wird der eingehende Datenstrom vollständig gelesen und auf Arbeitsspeicher oder Datenträger gepuffert (abhängig von den Einstellungen).

Empfehlung: Dies kann durch Anwenden von Endpunktmetadaten aktiviert werden, die die IPreBufferRequestStreamMetadata Schnittstelle implementieren. Dies ist als Attribut PreBufferRequestStreamAttribute verfügbar, das auf Controller oder Methoden angewendet werden kann.

Um dies auf allen MVC-Endpunkten zu aktivieren, gibt es eine Erweiterungsmethode, die wie folgt verwendet werden kann:

app.MapDefaultControllerRoute()
    .PreBufferRequestStream();

Pufferung des Antwortdatenstroms

Einige APIs auf Response erfordern, dass der Ausgabestream gepuffert ist, wie bei Output, End(), Clear() und SuppressContent.

Empfehlung: Um das Verhalten zu unterstützen, wenn Response eine Pufferung der Antwort vor dem Senden erfordert, müssen Endpunktmetadaten implementiert werden, indem die Endpunkte sich dafür entscheiden, indem sie IBufferResponseStreamMetadata einsetzen.

Um dies auf allen MVC-Endpunkten zu aktivieren, gibt es eine Erweiterungsmethode, die wie folgt verwendet werden kann:

app.MapDefaultControllerRoute()
    .BufferResponseStream();

Vollständiges Umschreiben in ASP.NET Core HttpContext

Wählen Sie diesen Ansatz aus, wenn Sie eine vollständige Migration durchführen und httpContext-bezogenen Code neu schreiben können, um die systemeigene Implementierung von ASP.NET Core zu verwenden.

ASP.NET HttpContext von Core bietet einen modulareren und erweiterbareren Entwurf im Vergleich zu ASP.NET Framework. Dieser Ansatz bietet die beste Leistung, erfordert aber während der Migration mehr Codeänderungen.

Überblick

HttpContext hat sich in ASP.NET Core deutlich verändert. Beim Migrieren von HTTP-Modulen oder Handlern zu Middleware müssen Sie Ihren Code aktualisieren, um mit der neuen HttpContext API zu arbeiten.

In ASP.NET Core Middleware verwendet die Invoke Methode einen Parameter vom Typ HttpContext:

public async Task Invoke(HttpContext context)

Dies HttpContext unterscheidet sich von der ASP.NET Framework-Version und erfordert unterschiedliche Ansätze für den Zugriff auf Anforderungs- und Antwortinformationen.

Eigenschaftsübersetzungen

In diesem Abschnitt wird gezeigt, wie Sie die am häufigsten verwendeten Eigenschaften System.Web.HttpContext in ASP.NET Core in das Äquivalent Microsoft.AspNetCore.Http.HttpContext übersetzen.

HttpContext-Eigenschaften

HttpRequest-Eigenschaften

  • 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.RawUrlMehrere Eigenschaften

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

    Verwenden Sie 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"];
    }
    

    Warnung: Formularwerte nur lesen, wenn der Inhaltstyp "x-www-form-urlencoded" oder "Formulardaten" ist

  • HttpRequest.InputStreamHttpRequest.Body

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

    Warnung: Nur am Ende der Pipeline in der Handler-Middleware verwenden. Der Inhalt kann nur einmal pro Anforderung gelesen werden.

HttpResponse-Eigenschaften

  • 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.TransmitFileAnforderungsfeatures anzeigen

    Die Bereitstellung von Dateien wird in anforderungsfeatures in ASP.NET Core erläutert.

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

    Muss rückrufmuster verwenden, um Kopfzeilen festzulegen, bevor die Antwort gestartet wird

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

    Muss das Callback-Muster verwenden, um Cookies zu setzen, bevor die Antwort beginnt.

  • Festlegen von Antwortheadern:

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

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-Adapter

Hinweis

Dadurch werden die System.Web Adapter verwendet, um die Migration zu vereinfachen.

Wählen Sie diesen Ansatz aus, wenn Sie über eine umfangreiche HttpContext-Verwendung in freigegebenen Bibliotheken verfügen oder eine inkrementelle Migration durchführen, bei der Sie Codeänderungen minimieren möchten.

Die System.Web-Adapter bieten eine Kompatibilitätsebene, mit der Sie vertraute HttpContext APIs in ASP.NET Core-Anwendungen verwenden können. Dieser Ansatz ist besonders nützlich, wenn:

  • Sie verfügen über freigegebene Bibliotheken, die HttpContext
  • Sie führen eine inkrementelle Migration aus
  • Sie möchten Codeänderungen während des Migrationsprozesses minimieren.

Vorteile der Verwendung von System.Web-Adaptern

  • Minimale Codeänderungen: Beibehalten ihrer vorhandenen System.Web.HttpContext Verwendungsmuster
  • Freigegebene Bibliotheken: Bibliotheken können sowohl mit ASP.NET Framework als auch mit ASP.NET Core arbeiten.
  • Inkrementelle Migration: Anwendungen schrittweise migrieren, ohne dabei gemeinsame Abhängigkeiten zu beeinträchtigen
  • Schnellere Migration: Verringern Der Zeitaufwand für die Migration komplexer Anwendungen

Überlegungen

  • Leistung: Obwohl gut, verursachen Adapter im Vergleich zu nativen ASP.NET Core-APIs zusätzlichen Overhead.
  • Featureparität: Nicht alle HttpContext Features sind über Adapter verfügbar
  • Langfristige Strategie: Erwägen Sie schließlich die Migration zu systemeigenen ASP.NET Core-APIs, um optimale Leistung zu erzielen.

Weitere Informationen zu System.Web-Adaptern finden Sie in der Dokumentation zu System.Web-Adaptern.

Weitere Ressourcen