Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
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:
- ASP.NET Framework wird mit integrierten Eigenschaften und Methoden verwendet System.Web.HttpContext
- ASP.NET Core verwendet Microsoft.AspNetCore.Http.HttpContext ein modulares, erweiterbares Design
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:
- Vollständige Neuschreibung - Schreiben Sie den gesamten HttpContext-Code neu, um die native HttpContext-Implementierung von ASP.NET Core zu verwenden.
- 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:
Führen Sie eine vollständige Neuschreibung oder inkrementelle Migration durch?
- Vollständige Neuschreibung → Vollständige Neuschreibung in ASP.NET Core HttpContext
- Inkrementelle Migration → Frage 2 fortsetzen
Haben Sie eine umfangreiche HttpContext-Nutzung für gemeinsame Bibliotheken?
- Ja, viele gemeinsam genutzte Code → System.Web-Adapter
- Nein, isolierte HttpContext-Verwendung → Vollständige Neuschreibung in ASP.NET Core HttpContext
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
HttpContext.Items → HttpContext.Items
IDictionary<object, object> items = httpContext.Items;Keine gleichwertige → HttpContext.TraceIdentifier
string requestId = httpContext.TraceIdentifier;Eindeutige Anforderungs-ID für die Protokollierung
HttpRequest-Eigenschaften
HttpRequest.HttpMethod → HttpRequest.Method
string httpMethod = httpContext.Request.Method;HttpRequest.QueryString → HttpRequest.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.RawUrl → Mehrere Eigenschaften
// using Microsoft.AspNetCore.Http.Extensions; var url = httpContext.Request.GetDisplayUrl();Verwenden Sie Request.Scheme, Host, PathBase, Path, QueryString
HttpRequest.IsSecureConnection → HttpRequest.IsHttps
var isSecureConnection = httpContext.Request.IsHttps;HttpRequest.UserHostAddress → ConnectionInfo.RemoteIpAddress
var userHostAddress = httpContext.Connection.RemoteIpAddress?.ToString();HttpRequest.Cookies → HttpRequest.Cookies
IRequestCookieCollection cookies = httpContext.Request.Cookies; string unknownCookieValue = cookies["unknownCookie"]; // will be null (no exception) string knownCookieValue = cookies["cookie1name"]; // will be actual valueHttpRequest.RequestContext → RoutingHttpContextExtensions.GetRouteData
var routeValue = httpContext.GetRouteValue("key");HttpRequest.Headers → HttpRequest.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.UserAgent → HttpRequest.Headers
string userAgent = headersDictionary[HeaderNames.UserAgent].ToString();HttpRequest.UrlReferrer → HttpRequest.Headers
string urlReferrer = headersDictionary[HeaderNames.Referer].ToString();HttpRequest.ContentType → HttpRequest.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.Form → HttpRequest.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.InputStream → HttpRequest.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.StatusDescription → HttpResponse.StatusCode
// using Microsoft.AspNetCore.Http; httpContext.Response.StatusCode = StatusCodes.Status200OK;HttpResponse.ContentEncoding / HttpResponse.ContentType → HttpResponse.ContentType
// using Microsoft.Net.Http.Headers; var mediaType = new MediaTypeHeaderValue("application/json"); mediaType.Encoding = System.Text.Encoding.UTF8; httpContext.Response.ContentType = mediaType.ToString();HttpResponse.ContentType → HttpResponse.ContentType
httpContext.Response.ContentType = "text/html";HttpResponse.Output → HttpResponseWritingExtensions.WriteAsync
string responseContent = GetResponseContent(); await httpContext.Response.WriteAsync(responseContent);HttpResponse.TransmitFile → Anforderungsfeatures anzeigen
Die Bereitstellung von Dateien wird in anforderungsfeatures in ASP.NET Core erläutert.
HttpResponse.Headers → HttpResponse.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.Cookies → HttpResponse.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.HttpContextVerwendungsmuster - 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.