Ereignisse
Power BI DataViz Weltmeisterschaften
14. Feb., 16 Uhr - 31. März, 16 Uhr
Mit 4 Chancen, ein Konferenzpaket zu gewinnen und es zum LIVE Grand Finale in Las Vegas zu machen
Weitere InformationenDieser Browser wird nicht mehr unterstützt.
Führen Sie ein Upgrade auf Microsoft Edge durch, um die neuesten Features, Sicherheitsupdates und den technischen Support zu nutzen.
Hinweis
Dies ist nicht die neueste Version dieses Artikels. Die aktuelle Version finden Sie in der .NET 9-Version dieses Artikels.
Warnung
Diese Version von ASP.NET Core wird nicht mehr unterstützt. Weitere Informationen finden Sie in der .NET- und .NET Core-Supportrichtlinie. Die aktuelle Version finden Sie in der .NET 9-Version dieses Artikels.
Wichtig
Diese Informationen beziehen sich auf ein Vorabversionsprodukt, das vor der kommerziellen Freigabe möglicherweise noch wesentlichen Änderungen unterliegt. Microsoft gibt keine Garantie, weder ausdrücklich noch impliziert, hinsichtlich der hier bereitgestellten Informationen.
Die aktuelle Version finden Sie in der .NET 9-Version dieses Artikels.
Von Mike Rousos
Dieser Artikel bietet Informationen zur Maximierung der Leistung und Zuverlässigkeit von ASP.NET Core-Apps.
Die Zwischenspeicherung wird in mehreren Teilen dieses Artikels besprochen. Weitere Informationen finden Sie unter Übersicht über das Zwischenspeichern in ASP.NET Core.
In diesem Artikel ist der langsamste Codepfad als ein Codepfad definiert, der sehr häufig aufgerufen wird und in dem der Großteil der Ausführung erfolgt. Der langsamste Codepfad begrenzt üblicherweise die horizontale Skalierung und die Leistung einer App und wird in verschiedenen Teilen dieses Artikels besprochen.
ASP.NET Core-Apps sollten so konzipiert werden, dass viele Anforderungen gleichzeitig verarbeitet werden können. Asynchrone APIs ermöglichen die parallele Verarbeitung Tausender Anforderungen in einem kleinen Pool von Threads, indem nicht auf blockierende Aufrufe gewartet wird. Anstatt darauf zu warten, dass eine synchrone Aufgabe mit langer Laufzeit abgeschlossen wird, kann der Thread eine andere Anforderung bearbeiten.
Ein häufiges Leistungsproblem in ASP.NET Core-Apps sind blockierende Aufrufe, die asynchron sein könnten. Viele synchrone blockierende Aufrufe führen zu einem Threadmangel im Pool und zu längeren Antwortzeiten.
Blockieren Sie die asynchrone Ausführung nicht durch Aufrufen von Task.Wait oder Task<TResult>.Result.
Rufen Sie keine Sperren in häufig verwendeten Codepfaden ab. ASP.NET Core-Apps weisen die beste Leistung auf, wenn sie für die parallele Ausführung von Code konzipiert sind.
Rufen Sie nichtTask.Run auf und warten unmittelbar auf seinen Abschluss. ASP.NET Core führt App-Code bereits in normalen Threads im Threadpool aus, daher führt ein Aufruf von Task.Run
nur zu einer unnötigen zusätzlichen Reservierung des Threadpools. Auch wenn der geplante Code einen Thread blockieren würde, wird dies durch Task.Run
nicht verhindert.
Über einen Profiler wie z. B. PerfView können Threads ermittelt werden, die dem Threadpool häufig hinzugefügt werden. Das Microsoft-Windows-DotNETRuntime/ThreadPoolWorkerThread/Start
-Ereignis gibt einen Thread an, der dem Threadpool hinzugefügt wurde.
Eine Webseite sollte große Datenmengen nicht gleichzeitig laden. Berücksichtigen Sie beim Zurückgeben einer Auflistung von Objekten, ob dies zu Leistungsproblemen führen könnte. Ermitteln Sie, ob der Entwurf die folgenden unerwünschten Ergebnisse erzielen könnte:
Fügen Sie eine Paginierung hinzu, um die vorherigen Szenarien abzumildern. Bei der Verwendung von Seitenformat- und Seitenindexparametern sollten Entwickler das Design bevorzugen, bei dem Teilergebnisse zurückgegeben werden. Wenn ein vollständiges Ergebnis erforderlich ist, sollte die Paginierung verwendet werden, um Ergebnisbatches asynchron aufzufüllen und so das Sperren von Serverressourcen zu vermeiden.
Weitere Informationen zur Paginierung und zum Beschränken der Anzahl der zurückgegebenen Datensätze finden Sie hier:
Das Zurückgeben von IEnumerable<T>
aus einer Aktion führt zu einer synchronen Sammlungsiteration durch das Serialisierungsmodul. Das Ergebnis sind die Blockierung von Aufrufen und die potenzielle Außerkraftsetzung des Threadpools. Um eine synchrone Enumeration zu vermeiden, verwenden Sie ToListAsync
vor dem Zurückgeben der Enumeration.
Ab ASP.NET Core 3.0 kann IAsyncEnumerable<T>
als Alternative zum IEnumerable<T>
-Element verwendet werden, das asynchron enumeriert. Weitere Informationen finden Sie unter Controller – Aktionsrückgabetypen.
Der .NET Core Garbage Collector verwaltet die Belegung und Freigabe von Arbeitsspeichers in ASP.NET Core-Apps automatisch. Eine automatische Garbage Collection bedeutet im Allgemeinen, dass Entwickler sich keine Gedanken darüber machen müssen, wie oder wann Arbeitsspeicher freigegeben wird. Das Bereinigen nicht referenzierter Objekte erfordert jedoch CPU-Zeit, sodass Entwickler die Zuteilung von Objekten im langsamsten Codepfad minimieren sollten. Die Garbage Collection ist bei großen Objekten (> = 85.000 KB) besonders ressourcenintensiv. Große Objekte werden im Heap für große Objekte gespeichert und erfordern zur Bereinigung eine vollständige Garbage Collection (Generation 2). Im Gegensatz zu den Garbage Collections der Generationen 0 und 1 erfordert eine Collection der Generation 2 die temporäre Aussetzung der App-Ausführung. Die häufige Zuteilung und Aufhebung der Zuteilung großer Objekte kann zu einer inkonsistenten Leistung führen.
Empfehlungen:
Arbeitsspeicherprobleme wie die oben genannten können durch Überprüfen der Garbage Collection-Statistiken (GC) in PerfView diagnostiziert werden. Untersuchen Sie Folgendes:
Weitere Informationen finden Sie unter Garbage Collection und Leistung.
Interaktionen mit Datenspeicher- und anderen Remotediensten sind häufig die langsamsten Teile einer ASP.NET Core-App. Das effiziente Lesen und Schreiben von Daten ist für eine gute Leistung von entscheidender Bedeutung.
Empfehlungen:
.Where
-, .Select
- oder .Sum
-Anweisungen), sodass die Filterung von der Datenbank durchgeführt wird.Die folgenden Ansätze können die Leistung in Apps mit einem hohen Maß an Skalierung verbessern:
Es wird empfohlen, die Auswirkungen der oben beschriebenen Ansätze für hohe Leistung vor dem Committen der Codebasis zu messen. Die zusätzliche Komplexität kompilierter Abfragen wiegt die Leistungsverbesserung möglicherweise nicht auf.
Abfrageprobleme lassen sich ermitteln, indem überprüft wird, wie viel Zeit für den Zugriff auf Daten mit Application Insights oder mit Profilerstellungstools aufgewendet wird. Die meisten Datenbanken stellen auch Statistiken zu häufig ausgeführten Abfragen zur Verfügung.
Obwohl HttpClient die IDisposable
-Schnittstelle implementiert, ist die Klasse für die Wiederverwendung konzipiert. Geschlossene HttpClient
-Instanzen lassen Sockets für einen kurzen Zeitraum im Zustand TIME_WAIT
offen. Wenn ein Codepfad, der HttpClient
-Objekte erstellt und löscht, häufig verwendet wird, stehen möglicherweise nicht genügend Sockets für die App zur Verfügung. HttpClientFactory
wurde in ASP.NET Core 2.1 als Lösung für dieses Problem eingeführt. Die Factory verarbeitet HTTP-Poolingverbindungen, um die Leistung und Zuverlässigkeit zu optimieren. Weitere Informationen finden Sie unter Verwenden von HttpClientFactory
zum Implementieren resilienter HTTP-Anforderungen.
Empfehlungen:
HttpClient
direkt.HttpClient
-Instanzen abzurufen. Weitere Informationen finden Sie unter Verwenden von HttpClientFactory zum Implementieren robuster HTTP-Anforderungen.Sie möchten, dass Ihr gesamter Code schnell verarbeitet wird. Häufig aufgerufene Codepfade sind diejenigen, deren Optimierung am wichtigsten ist. Dazu zählen unter anderem folgende Einstellungen:
Empfehlungen:
Die meisten Anforderungen an eine ASP.NET Core-App können von einem Controller oder Seitenmodell verarbeitet werden, der/das erforderliche Dienste aufruft und eine HTTP-Antwort zurückgibt. Bei einigen Anforderungen, die Aufgaben mit langer Ausführungsdauer umfassen, ist es besser, den gesamten Anforderungs-/Antwortprozess asynchron zu gestalten.
Empfehlungen:
ASP.NET Core-Apps mit komplexen Front-Ends verarbeiten häufig viele JavaScript-, CSS- oder Bilddateien. Die Leistung der anfänglichen Ladeanforderungen kann durch Folgendes verbessert werden:
Empfehlungen:
environment
von ASP.NET Core zum Verarbeiten von Development
- und Production
-Umgebungen verwendet wird.Eine Reduzierung der Antwortgröße steigert in der Regel die Reaktionsfähigkeit einer App, häufig sogar erheblich. Eine Möglichkeit zum Verringern der Nutzdatengrößen besteht darin, die Antworten einer App zu komprimieren. Weitere Informationen finden Sie unter Antwortkomprimierung.
Jedes neue Release von ASP.NET Core umfasst Leistungsverbesserungen. Optimierungen in .NET Core und ASP.NET Core bedeuten, dass neuere Versionen im Allgemeinen eine bessere Leistung bieten als ältere Versionen. Beispielsweise wurde in .NET Core 2.1 Unterstützung für kompilierte reguläre Ausdrücke hinzugefügt, und diese Version profitiert von Span<T>. In ASP.NET Core 2.2 wurde Unterstützung für HTTP/2 hinzugefügt. ASP.NET Core 3.0 enthält viele Verbesserungen, die die Arbeitsspeichernutzung reduzieren und den Durchsatz erhöhen. Wenn Leistung hohe Priorität hat, sollten Sie ein Upgrade auf die aktuelle Version von ASP.NET Core in Betracht ziehen.
Ausnahmen sollten nur selten vorkommen. Das Auslösen und Abfangen von Ausnahmen ist in Relation zu anderen Codeflowmustern langsam. Aus diesem Grund sollten Ausnahmen nicht verwendet werden, um den normalen Programmflow zu steuern.
Empfehlungen:
App-Diagnosetools wie Application Insights können dabei helfen, häufige Ausnahmen in einer App zu identifizieren, die sich auf die Leistung auswirken können.
Alle E/A-Vorgänge in ASP.NET Core laufen asynchron ab. Server implementieren die Stream
-Schnittstelle, die sowohl synchrone als auch asynchrone Überladungen bietet. Die asynchronen Überladungen sollten bevorzugt werden, um das Blockieren von Threadpoolthreads zu vermeiden. Das Blockieren von Threads kann zu einem Threadpoolmangel führen.
Gehen Sie nicht wie folgt vor: Das folgende Beispiel verwendet die Methode ReadToEnd. Diese blockiert den aktuellen Thread, um auf das Ergebnis zu warten. Dies ist ein Beispiel für das Prinzip synchron statt asynchron.
public class BadStreamReaderController : Controller
{
[HttpGet("/contoso")]
public ActionResult<ContosoData> Get()
{
var json = new StreamReader(Request.Body).ReadToEnd();
return JsonSerializer.Deserialize<ContosoData>(json);
}
}
Im vorherigen Code liest Get
den gesamten HTTP-Anforderungstext synchron in den Arbeitsspeicher. Wenn der Uploadvorgang auf dem Client nur langsam erfolgt, verfährt die App nach dem Prinzip „synchron statt asynchron“. Die App geht so vor, weil KestrelKEINE synchronen Lesevorgänge unterstützt.
Gehen Sie folgendermaßen vor: Das folgende Beispiel verwendet ReadToEndAsync und blockiert den Thread beim Lesen nicht.
public class GoodStreamReaderController : Controller
{
[HttpGet("/contoso")]
public async Task<ActionResult<ContosoData>> Get()
{
var json = await new StreamReader(Request.Body).ReadToEndAsync();
return JsonSerializer.Deserialize<ContosoData>(json);
}
}
Der oben stehende Code liest den gesamten HTTP-Anforderungstext asynchron in den Arbeitsspeicher.
Warnung
Bei umfangreichen Anforderungen kann das Lesen des gesamten HTTP-Anforderungstexts in den Arbeitsspeicher zu einer OOM-Bedingung (Out of Memory, nicht genügend Arbeitsspeicher) führen. OOM kann zu einer Dienstblockade (Denial Of Service) führen. Weitere Informationen finden Sie unter Vermeiden des Lesens umfangreicher Anforderungs- oder Antworttexte in den Arbeitsspeicher in diesem Artikel.
Gehen Sie folgendermaßen vor: Das folgende Beispiel ist vollständig asynchron und verwendet einen nicht gepufferten Anforderungstext:
public class GoodStreamReaderController : Controller
{
[HttpGet("/contoso")]
public async Task<ActionResult<ContosoData>> Get()
{
return await JsonSerializer.DeserializeAsync<ContosoData>(Request.Body);
}
}
Der obige Code deserialisiert den Anforderungstext asynchron in ein C#-Objekt.
Verwenden Sie HttpContext.Request.ReadFormAsync
anstelle von HttpContext.Request.Form
.
HttpContext.Request.Form
kann nur mit den folgenden Bedingungen sicher gelesen werden:
ReadFormAsync
gelesen.HttpContext.Request.Form
gelesen.Gehen Sie nicht wie folgt vor: Das folgende Beispiel verwendet HttpContext.Request.Form
. HttpContext.Request.Form
verfährt nach dem Prinzip synchron statt asynchron und kann zu einem Threadpoolmangel führen.
public class BadReadController : Controller
{
[HttpPost("/form-body")]
public IActionResult Post()
{
var form = HttpContext.Request.Form;
Process(form["id"], form["name"]);
return Accepted();
}
Gehen Sie folgendermaßen vor: Das folgende Beispiel verwendet HttpContext.Request.ReadFormAsync
, um den Formulartext asynchron zu lesen.
public class GoodReadController : Controller
{
[HttpPost("/form-body")]
public async Task<IActionResult> Post()
{
var form = await HttpContext.Request.ReadFormAsync();
Process(form["id"], form["name"]);
return Accepted();
}
In .NET gelangt jede Objektzuteilung mit einer Größe von mindestens 85.000 Bytes in den Heap für große Objekte (Large Object Heap, LOH). Große Objekte sind aus zwei Gründen teuer:
Dieser Blogbeitrag bietet eine prägnante Beschreibung des Problems:
Wenn ein großes Objekt zugeordnet wird, wird es als Gen 2-Objekt markiert, nicht als Gen 0, wie bei kleinen Objekten. Daraus folgt: Wenn im LOH nicht mehr genügend Arbeitsspeicher vorhanden ist, bereinigt die Garbage Collection den gesamten verwalteten Heap, nicht nur den LOH. Es werden also alle Gen 0-, Gen 1- und Gen 2-Objekte bereinigt, einschließlich des LOH. Dies wird als vollständige Garbage Collection bezeichnet und ist die zeitaufwendigste Garbage Collection. Für viele Anwendungen kann dies akzeptabel sein. Keinesfalls akzeptabel ist es allerdings für Hochleistungswebserver, bei denen nur wenige große Arbeitsspeicherpuffer benötigt werden, um eine durchschnittliche Webanforderung zu verarbeiten (Lesen aus einem Socket, Dekomprimieren, Decodieren von JSON und weitere Vorgänge).
Speichern eines großen Anforderungs- oder Antworttexts in einem einzigen byte[]
- oder string
-Wert:
Gehen Sie bei Verwendung eines Serialisierungs-/Deserialisierungsmoduls, das nur synchrone Lese- und Schreibvorgänge unterstützt (z. B. Json.NET) folgendermaßen vor:
Warnung
Eine umfangreiche Anforderung kann zu einer OOM-Bedingung (Out of Memory, nicht genügend Arbeitsspeicher) führen. OOM kann zu einer Dienstblockade (Denial Of Service) führen. Weitere Informationen finden Sie unter Vermeiden des Lesens umfangreicher Anforderungs- oder Antworttexte in den Arbeitsspeicher in diesem Artikel.
ASP.NET Core 3.0 verwendet jetzt standardmäßig System.Text.Json zur JSON-Serialisierung. System.Text.Json:
Newtonsoft.Json
erzielen.Der IHttpContextAccessor.HttpContext gibt den HttpContext
der aktiven Anforderung zurück, wenn der Zugriff aus dem Anforderungsthread erfolgt. Der IHttpContextAccessor.HttpContext
sollte nicht in einem Feld oder einer Variable gespeichert werden.
Gehen Sie nicht wie folgt vor: Das folgende Beispiel speichert den HttpContext
in einem Feld und versucht ihn dann später zu verwenden.
public class MyBadType
{
private readonly HttpContext _context;
public MyBadType(IHttpContextAccessor accessor)
{
_context = accessor.HttpContext;
}
public void CheckAdmin()
{
if (!_context.User.IsInRole("admin"))
{
throw new UnauthorizedAccessException("The current user isn't an admin");
}
}
}
Der vorangehende Code erfasst häufig einen NULL- oder falschen HttpContext
im Konstruktor.
Gehen Sie folgendermaßen vor: Das folgende Beispiel führt Folgendes aus:
HttpContext
zur richtigen Zeit und prüft auf null
.public class MyGoodType
{
private readonly IHttpContextAccessor _accessor;
public MyGoodType(IHttpContextAccessor accessor)
{
_accessor = accessor;
}
public void CheckAdmin()
{
var context = _accessor.HttpContext;
if (context != null && !context.User.IsInRole("admin"))
{
throw new UnauthorizedAccessException("The current user isn't an admin");
}
}
}
HttpContext
ist nicht threadsicher. Der parallele Zugriff auf HttpContext
aus mehreren Threads kann zu unerwartetem Verhalten führen, wie z. B. Server reagiert nicht mehr, Abstürze und Datenbeschädigung.
Gehen Sie nicht wie folgt vor: Das folgende Beispiel führt drei parallele Anforderungen aus und protokolliert den eingehenden Anforderungspfad vor und nach der ausgehenden HTTP-Anforderung. Mehrere Threads greifen möglicherweise parallel auf den Anforderungspfad zu.
public class AsyncBadSearchController : Controller
{
[HttpGet("/search")]
public async Task<SearchResults> Get(string query)
{
var query1 = SearchAsync(SearchEngine.Google, query);
var query2 = SearchAsync(SearchEngine.Bing, query);
var query3 = SearchAsync(SearchEngine.DuckDuckGo, query);
await Task.WhenAll(query1, query2, query3);
var results1 = await query1;
var results2 = await query2;
var results3 = await query3;
return SearchResults.Combine(results1, results2, results3);
}
private async Task<SearchResults> SearchAsync(SearchEngine engine, string query)
{
var searchResults = _searchService.Empty();
try
{
_logger.LogInformation("Starting search query from {path}.",
HttpContext.Request.Path);
searchResults = _searchService.Search(engine, query);
_logger.LogInformation("Finishing search query from {path}.",
HttpContext.Request.Path);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed query from {path}",
HttpContext.Request.Path);
}
return await searchResults;
}
Gehen Sie folgendermaßen vor: Das folgende Beispiel kopiert alle Daten aus der eingehenden Anforderung, bevor die drei parallelen Anforderungen ausgeführt werden.
public class AsyncGoodSearchController : Controller
{
[HttpGet("/search")]
public async Task<SearchResults> Get(string query)
{
string path = HttpContext.Request.Path;
var query1 = SearchAsync(SearchEngine.Google, query,
path);
var query2 = SearchAsync(SearchEngine.Bing, query, path);
var query3 = SearchAsync(SearchEngine.DuckDuckGo, query, path);
await Task.WhenAll(query1, query2, query3);
var results1 = await query1;
var results2 = await query2;
var results3 = await query3;
return SearchResults.Combine(results1, results2, results3);
}
private async Task<SearchResults> SearchAsync(SearchEngine engine, string query,
string path)
{
var searchResults = _searchService.Empty();
try
{
_logger.LogInformation("Starting search query from {path}.",
path);
searchResults = await _searchService.SearchAsync(engine, query);
_logger.LogInformation("Finishing search query from {path}.", path);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed query from {path}", path);
}
return await searchResults;
}
HttpContext
ist nur gültig, solange eine aktive HTTP-Anforderung in der ASP.NET Core-Pipeline vorhanden ist. Die gesamte ASP.NET Core-Pipeline ist eine asynchrone Kette aus Delegaten, die jede Anforderung ausführt. Wenn die von dieser Kette zurückgegebene Task
abgeschlossen ist, wird der HttpContext
neu gestartet.
Gehen Sie nicht wie folgt vor: Das folgende Beispiel verwendet async void
, wodurch die HTTP-Anforderung abgeschlossen wird, wenn das erste await
-Element erreicht ist:
async void
ist IMMER eine schlechte Gepflogenheit in ASP.NET Core-Apps.HttpResponse
zu, nachdem die HTTP-Anforderung abgeschlossen ist.public class AsyncBadVoidController : Controller
{
[HttpGet("/async")]
public async void Get()
{
await Task.Delay(1000);
// The following line will crash the process because of writing after the
// response has completed on a background thread. Notice async void Get()
await Response.WriteAsync("Hello World");
}
}
Gehen Sie folgendermaßen vor: Das folgende Beispiel gibt eine Task
an das Framework zurück, sodass die HTTP-Anforderung erst abgeschlossen wird, wenn die Aktion abgeschlossen ist.
public class AsyncGoodTaskController : Controller
{
[HttpGet("/async")]
public async Task Get()
{
await Task.Delay(1000);
await Response.WriteAsync("Hello World");
}
}
Gehen Sie nicht wie folgt vor: Das folgende Beispiel zeigt eine Schließung, die den HttpContext
aus der Controller
-Eigenschaft erfasst. Dies ist eine schlechte Gepflogenheit, weil für das Arbeitselement Folgendes passieren könnte:
HttpContext
zu lesen.[HttpGet("/fire-and-forget-1")]
public IActionResult BadFireAndForget()
{
_ = Task.Run(async () =>
{
await Task.Delay(1000);
var path = HttpContext.Request.Path;
Log(path);
});
return Accepted();
}
Gehen Sie folgendermaßen vor: Das folgende Beispiel führt Folgendes aus:
[HttpGet("/fire-and-forget-3")]
public IActionResult GoodFireAndForget()
{
string path = HttpContext.Request.Path;
_ = Task.Run(async () =>
{
await Task.Delay(1000);
Log(path);
});
return Accepted();
}
Hintergrundaufgaben sollten als gehostete Dienste implementiert werden. Weitere Informationen finden Sie unter Hintergrundaufgaben mit gehosteten Diensten.
Gehen Sie nicht wie folgt vor: Das folgende Beispiel zeigt eine Schließung, die den DbContext
aus dem Controller
-Aktionsparameter erfasst. Dies ist eine schlechte Gepflogenheit. Das Arbeitselement könnte außerhalb des Anforderungsbereichs ausgeführt werden. Der Bereich für den ContosoDbContext
ist auf die Anforderung festgelegt, was zu einer ObjectDisposedException
führt.
[HttpGet("/fire-and-forget-1")]
public IActionResult FireAndForget1([FromServices]ContosoDbContext context)
{
_ = Task.Run(async () =>
{
await Task.Delay(1000);
context.Contoso.Add(new Contoso());
await context.SaveChangesAsync();
});
return Accepted();
}
Gehen Sie folgendermaßen vor: Das folgende Beispiel führt Folgendes aus:
IServiceScopeFactory
ist ein Singleton.ContosoDbContext
aus der eingehenden Anforderung.[HttpGet("/fire-and-forget-3")]
public IActionResult FireAndForget3([FromServices]IServiceScopeFactory
serviceScopeFactory)
{
_ = Task.Run(async () =>
{
await Task.Delay(1000);
await using (var scope = serviceScopeFactory.CreateAsyncScope())
{
var context = scope.ServiceProvider.GetRequiredService<ContosoDbContext>();
context.Contoso.Add(new Contoso());
await context.SaveChangesAsync();
}
});
return Accepted();
}
Der hervorgehobene Code führt Folgendes aus:
ContosoDbContext
aus dem richtigen Bereich.[HttpGet("/fire-and-forget-3")]
public IActionResult FireAndForget3([FromServices]IServiceScopeFactory
serviceScopeFactory)
{
_ = Task.Run(async () =>
{
await Task.Delay(1000);
await using (var scope = serviceScopeFactory.CreateAsyncScope())
{
var context = scope.ServiceProvider.GetRequiredService<ContosoDbContext>();
context.Contoso.Add(new Contoso());
await context.SaveChangesAsync();
}
});
return Accepted();
}
ASP.NET Core puffert den HTTP-Antworttext nicht. Wenn die Antwort zum ersten Mal geschrieben wird, passiert Folgendes:
Gehen Sie nicht wie folgt vor: Der folgende Code versucht, Antwortheader hinzuzufügen, nachdem die Antwort bereits gestartet wurde:
app.Use(async (context, next) =>
{
await next();
context.Response.Headers["test"] = "test value";
});
Im vorherigen Code löst context.Response.Headers["test"] = "test value";
eine Ausnahme aus, wenn next()
in die Antwort geschrieben hat.
Gehen Sie folgendermaßen vor: Das folgende Beispiel überprüft, ob die HTTP-Antwort gestartet wurde, bevor die Header geändert werden.
app.Use(async (context, next) =>
{
await next();
if (!context.Response.HasStarted)
{
context.Response.Headers["test"] = "test value";
}
});
Gehen Sie folgendermaßen vor: Das folgende Beispiel verwendet HttpResponse.OnStarting
, um die Header festzulegen, bevor die Antwortheader an den Client geleert werden.
Die Überprüfung, ob die Antwort noch nicht gestartet wurde, ermöglicht die Registrierung eines Rückrufs, der unmittelbar vor dem Schreiben der Antwortheader aufgerufen wird. Die Überprüfung, ob die Antwort noch nicht gestartet wurde, ermöglicht Folgendes:
app.Use(async (context, next) =>
{
context.Response.OnStarting(() =>
{
context.Response.Headers["someheader"] = "somevalue";
return Task.CompletedTask;
});
await next();
});
Komponenten erwarten einen Aufruf nur dann, wenn sie die Antwort verarbeiten und bearbeiten können.
Beim Einsatz von In-Process-Hosting wird eine ASP.NET Core-App im gleichen Prozess wie ihr IIS-Arbeitsprozess ausgeführt. Das In-Process-Hosting bietet eine bessere Leistung als das Out-of-Process-Hosting, da Anforderungen nicht über den Loopbackadapter weitergeleitet werden. Der Loopbackadapter ist eine Netzwerkschnittstelle, die ausgehenden Netzwerkdatenverkehr zum selben Computer zurückleitet. IIS erledigt das Prozessmanagement mit dem Windows-Prozessaktivierungsdienst (Process Activation Service, WAS).
Projekte werden standardmäßig im In-Process-Hostingmodell in ASP.NET Core 3.0 und höher ausgeführt.
Weitere Informationen finden Sie unter Hosten von ASP.NET Core unter Windows mit IIS.
HttpRequest.ContentLength
ist NULL, wenn der Content-Length
-Header nicht empfangen wird. NULL bedeutet in diesem Fall, dass die Länge des Anforderungstexts nicht bekannt ist; es bedeutet nicht, dass die Länge null ist. Da alle Vergleiche mit NULL (mit Ausnahme von ==
) „false“ zurückgeben, kann der Vergleich Request.ContentLength > 1024
beispielsweise false
zurückgeben, wenn die Größe des Anforderungstexts 1024 übersteigt. Das Fehlen dieser Information kann zu Sicherheitslücken in Apps führen. Sie könnten denken, dass Sie sich vor zu umfangreichen Anfragen schützen, obwohl dies nicht der Fall ist.
Weitere Informationen finden Sie in dieser StackOverflow-Antwort.
Anleitungen zum Erstellen einer zuverlässigen, sicheren, leistungsfähigen, testbaren und skalierbaren ASP.NET Core-App finden Sie unter Enterprise Web App-Muster. Eine vollständige Beispielweb-App zur Produktionsqualität, die die Muster implementiert, ist verfügbar.
Feedback zu ASP.NET Core
ASP.NET Core ist ein Open Source-Projekt. Wählen Sie einen Link aus, um Feedback zu geben:
Ereignisse
Power BI DataViz Weltmeisterschaften
14. Feb., 16 Uhr - 31. März, 16 Uhr
Mit 4 Chancen, ein Konferenzpaket zu gewinnen und es zum LIVE Grand Finale in Las Vegas zu machen
Weitere Informationen