Zdarzenia
Power BI DataViz World Championships
14 lut, 16 - 31 mar, 16
Z 4 szans na wejście, można wygrać pakiet konferencji i zrobić go do LIVE Grand Finale w Las Vegas
Dowiedz się więcejTa przeglądarka nie jest już obsługiwana.
Przejdź na przeglądarkę Microsoft Edge, aby korzystać z najnowszych funkcji, aktualizacji zabezpieczeń i pomocy technicznej.
Uwaga
Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
Ważne
Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.
Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
Autor: Mike Rousos
Ten artykuł zawiera wskazówki dotyczące maksymalizacji wydajności i niezawodności aplikacji ASP.NET Core.
Buforowanie zostało omówione w kilku częściach tego artykułu. Aby uzyskać więcej informacji, zobacz Omówienie buforowania w programie ASP.NET Core.
W tym artykule ścieżka kodu gorąca jest definiowana jako ścieżka kodu, która jest często wywoływana i gdzie występuje znaczna część czasu wykonywania. Ścieżki kodu gorącego zwykle ograniczają skalowanie aplikacji w poziomie i wydajność i są omawiane w kilku częściach tego artykułu.
aplikacje ASP.NET Core powinny być projektowane w celu jednoczesnego przetwarzania wielu żądań. Asynchroniczne interfejsy API umożliwiają małą pulę wątków do obsługi tysięcy współbieżnych żądań, nie czekając na wywołania blokujące. Zamiast czekać na wykonanie długotrwałego zadania synchronicznego, wątek może pracować nad innym żądaniem.
Typowym problemem z wydajnością w aplikacjach ASP.NET Core jest blokowanie wywołań, które mogą być asynchroniczne. Wiele synchronicznych wywołań blokowania prowadzi do głodu puli wątków i obniżonych czasów odpowiedzi.
Nie blokuj wykonywania asynchronicznego przez wywołanie metody Task.Wait lub Task<TResult>.Result.
Nie pobieraj blokad w typowych ścieżkach kodu. aplikacje ASP.NET Core działają najlepiej, gdy są zaprojektowane do równoległego uruchamiania kodu.
Nie dzwonij Task.Run i natychmiast czekaj na nie. ASP.NET Core uruchamia już kod aplikacji w normalnych wątkach puli wątków, dlatego wywoływanie Task.Run
powoduje jedynie niepotrzebne planowanie puli wątków. Nawet jeśli zaplanowany kod zablokuje wątek, Task.Run
nie zapobiega temu.
Profiler, taki jak PerfView, może służyć do znajdowania wątków często dodawanych do puli wątków. Zdarzenie Microsoft-Windows-DotNETRuntime/ThreadPoolWorkerThread/Start
wskazuje wątek dodany do puli wątków.
Strona internetowa nie powinna ładować jednocześnie dużych ilości danych. Podczas zwracania kolekcji obiektów należy rozważyć, czy może to prowadzić do problemów z wydajnością. Ustal, czy projekt może wygenerować następujące słabe wyniki:
Dodaj stronicowanie, aby wyeliminować powyższe scenariusze. Korzystając z parametrów rozmiaru strony i indeksu strony, deweloperzy powinni faworyzować projekt zwracania częściowego wyniku. Gdy wymagany jest wyczerpujący wynik, stronicowanie powinno być używane do asynchronicznego wypełniania partii wyników, aby uniknąć blokowania zasobów serwera.
Aby uzyskać więcej informacji na temat stronicowania i ograniczania liczby zwracanych rekordów, zobacz:
IEnumerable<T>
Powrót z akcji powoduje synchroniczną iterację kolekcji przez serializator. Wynikiem jest blokowanie wywołań i potencjalna funkcja głodu puli wątków. Aby uniknąć synchronicznej wyliczenia, przed zwróceniem wyliczenia należy użyć ToListAsync
polecenia .
Począwszy od ASP.NET Core 3.0, IAsyncEnumerable<T>
można użyć jako alternatywy dla IEnumerable<T>
tego wyliczenia asynchronicznie. Aby uzyskać więcej informacji, zobacz Zwracane typy akcji kontrolera.
Moduł odśmieceń pamięci platformy .NET Core automatycznie zarządza alokacją i zwalnianiem pamięci w aplikacjach platformy ASP.NET Core. Automatyczne odzyskiwanie pamięci zwykle oznacza, że deweloperzy nie muszą martwić się o to, jak lub kiedy pamięć jest zwolniona. Jednak czyszczenie obiektów bez wnioskowania zajmuje czas procesora CPU, więc deweloperzy powinni zminimalizować przydzielanie obiektów w ścieżce kodu gorącego. Odzyskiwanie pamięci jest szczególnie kosztowne w przypadku dużych obiektów (>= 85 000 bajtów). Duże obiekty są przechowywane na stercie dużych obiektów i wymagają pełnego (2. generacji) odzyskiwania pamięci do wyczyszczenia. W przeciwieństwie do kolekcji generacji 0 i generacji 1 kolekcja generacji 2 wymaga tymczasowego zawieszenia wykonywania aplikacji. Częste przydzielanie i anulowanie alokacji dużych obiektów może spowodować niespójną wydajność.
Rekomendacje:
Problemy z pamięcią, takie jak poprzednie, można zdiagnozować, przeglądając statystyki odzyskiwania pamięci (GC) w programie PerfView i sprawdzając:
Aby uzyskać więcej informacji, zobacz Odzyskiwanie pamięci i wydajność.
Interakcje z magazynem danych i innymi usługami zdalnymi są często najwolniejszymi częściami aplikacji ASP.NET Core. Efektywne odczytywanie i zapisywanie danych ma kluczowe znaczenie dla dobrej wydajności.
Rekomendacje:
.Where
, .Select
lub .Sum
), aby filtrowanie było wykonywane przez bazę danych.Poniższe podejścia mogą zwiększyć wydajność aplikacji o dużej skali:
Zalecamy pomiar wpływu powyższych podejść o wysokiej wydajności przed zatwierdzeniem bazy kodu. Dodatkowa złożoność skompilowanych zapytań może nie uzasadniać poprawy wydajności.
Problemy z zapytaniami można wykryć, przeglądając czas spędzony na uzyskiwaniu dostępu do danych za pomocą usługi Application Insights lub za pomocą narzędzi profilowania. Większość baz danych udostępnia również statystyki dotyczące często wykonywanych zapytań.
Mimo że HttpClient implementuje IDisposable
interfejs, jest przeznaczony do ponownego użycia. Zamknięte HttpClient
wystąpienia pozostawiają gniazda otwarte w TIME_WAIT
stanie przez krótki czas. Jeśli ścieżka kodu, która tworzy i usuwa HttpClient
obiekty, jest często używana, aplikacja może wyczerpać dostępne gniazda.
HttpClientFactory
został wprowadzony w ASP.NET Core 2.1 jako rozwiązanie tego problemu. Obsługuje buforowanie połączeń HTTP w celu zoptymalizowania wydajności i niezawodności. Aby uzyskać więcej informacji, zobacz Używanie HttpClientFactory
do implementowania odpornych żądań HTTP.
Rekomendacje:
HttpClient
wystąpień bezpośrednio.HttpClient
. Aby uzyskać więcej informacji, zobacz Implementowanie odpornych żądań HTTP za pomocą elementu HttpClientFactory.Chcesz, aby cały kod był szybki. Często nazywane ścieżki kodu są najbardziej krytyczne do optymalizacji. Są to:
Rekomendacje:
Większość żądań do aplikacji ASP.NET Core może być obsługiwana przez kontroler lub model strony wywołujący niezbędne usługi i zwracając odpowiedź HTTP. W przypadku niektórych żądań obejmujących długotrwałe zadania lepiej jest wykonać cały proces odpowiedzi na żądanie asynchroniczne.
Rekomendacje:
ASP.NET aplikacje Core ze złożonymi frontonami często obsługują wiele plików javaScript, CSS lub image. Wydajność początkowych żądań ładowania można poprawić, wykonując następujące czynności:
Rekomendacje:
environment
ASP.NET Core do obsługi środowisk Development
i Production
.Zmniejszenie rozmiaru odpowiedzi zwykle zwiększa czas reakcji aplikacji, często dramatycznie. Jednym ze sposobów zmniejszenia rozmiarów ładunków jest kompresowanie odpowiedzi aplikacji. Aby uzyskać więcej informacji, zobacz Kompresja odpowiedzi.
Każda nowa wersja ASP.NET Core zawiera ulepszenia wydajności. Optymalizacje na platformie .NET Core i ASP.NET Core oznaczają, że nowsze wersje zwykle przewyższają starsze wersje. Na przykład platforma .NET Core 2.1 dodała obsługę skompilowanych wyrażeń regularnych i skorzystała z rozwiązania Span<T>. ASP.NET Core 2.2 dodano obsługę protokołu HTTP/2. ASP.NET Core 3.0 dodaje wiele ulepszeń , które zmniejszają użycie pamięci i zwiększają przepływność. Jeśli wydajność jest priorytetem, rozważ uaktualnienie do bieżącej wersji ASP.NET Core.
Wyjątki powinny być rzadkie. Zgłaszanie i przechwytywanie wyjątków jest powolne w stosunku do innych wzorców przepływu kodu. W związku z tym wyjątki nie powinny być używane do kontrolowania normalnego przepływu programu.
Rekomendacje:
Narzędzia diagnostyczne aplikacji, takie jak Application Insights, mogą pomóc w zidentyfikowaniu typowych wyjątków w aplikacji, które mogą mieć wpływ na wydajność.
Wszystkie operacje we/wy w ASP.NET Core są asynchroniczne. Serwery implementują Stream
interfejs, który ma zarówno synchroniczne, jak i asynchroniczne przeciążenia. Te asynchroniczne powinny być preferowane, aby uniknąć blokowania wątków puli wątków. Blokowanie wątków może prowadzić do głodu puli wątków.
Nie należy tego robić: W poniższym przykładzie użyto elementu ReadToEnd. Blokuje bieżący wątek do oczekiwania na wynik. Jest to przykład synchronizacji za pośrednictwem asynchronicznego.
public class BadStreamReaderController : Controller
{
[HttpGet("/contoso")]
public ActionResult<ContosoData> Get()
{
var json = new StreamReader(Request.Body).ReadToEnd();
return JsonSerializer.Deserialize<ContosoData>(json);
}
}
W poprzednim kodzie Get
synchronicznie odczytuje całą treść żądania HTTP do pamięci. Jeśli klient powoli przekazuje dane, aplikacja wykonuje synchronizację za pośrednictwem asynchronicznego. Aplikacja synchronizuje się za pośrednictwem asynchronicznego, ponieważ Kestrelnie obsługuje synchronicznych odczytów.
Wykonaj następujące czynności: w poniższym przykładzie użyto ReadToEndAsync metody i nie blokuje wątku podczas odczytywania.
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);
}
}
Poprzedni kod asynchronicznie odczytuje całą treść żądania HTTP do pamięci.
Ostrzeżenie
Jeśli żądanie jest duże, odczytywanie całej treści żądania HTTP do pamięci może prowadzić do braku pamięci (OOM). OOM może spowodować odmowę usługi. Aby uzyskać więcej informacji, zobacz Unikanie odczytywania dużych treści żądań lub treści odpowiedzi w pamięci w tym artykule.
Wykonaj następujące czynności: Poniższy przykład jest w pełni asynchroniczny przy użyciu niebuforowanej treści żądania:
public class GoodStreamReaderController : Controller
{
[HttpGet("/contoso")]
public async Task<ActionResult<ContosoData>> Get()
{
return await JsonSerializer.DeserializeAsync<ContosoData>(Request.Body);
}
}
Poprzedni kod asynchronicznie deselizuje treść żądania do obiektu języka C#.
Użyj HttpContext.Request.ReadFormAsync
zamiast HttpContext.Request.Form
.
HttpContext.Request.Form
można bezpiecznie odczytywać tylko z następującymi warunkami:
ReadFormAsync
iHttpContext.Request.Form
Nie należy tego robić: w poniższym przykładzie użyto metody HttpContext.Request.Form
.
HttpContext.Request.Form
używa synchronizacji za pośrednictwem asynchronicznego i może prowadzić do głodu puli wątków.
public class BadReadController : Controller
{
[HttpPost("/form-body")]
public IActionResult Post()
{
var form = HttpContext.Request.Form;
Process(form["id"], form["name"]);
return Accepted();
}
Wykonaj następujące czynności: poniższy przykład używa HttpContext.Request.ReadFormAsync
metody do asynchronicznego odczytywania treści formularza.
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();
}
Na platformie .NET każda alokacja obiektu większa lub równa 85 000 bajtów kończy się w dużym stercie obiektu (LOH). Duże obiekty są kosztowne na dwa sposoby:
W tym wpisie w blogu opisano problem zwięźle:
Po przydzieleniu dużego obiektu jest on oznaczony jako obiekt 2. generacji. Nie gen 0 jak w przypadku małych obiektów. Konsekwencje są to, że jeśli zabraknie pamięci w LOH, GC czyści całą zarządzaną stertę, nie tylko LOH. W ten sposób czyści gen 0, Gen 1 i Gen 2, w tym LOH. Jest to nazywane pełnym odzyskiwaniem pamięci i jest najbardziej czasochłonnym odzyskiwaniem pamięci. W przypadku wielu aplikacji może to być akceptowalne. Ale zdecydowanie nie w przypadku serwerów internetowych o wysokiej wydajności, gdzie do obsługi średniego żądania internetowego jest potrzebnych kilka dużych pamięci (odczyt z gniazda, dekompresuj, dekoduj kod JSON i nie tylko).
Przechowywanie dużej treści żądania lub odpowiedzi w jednym byte[]
lub string
:
W przypadku używania serializatora/de-serializatora, który obsługuje tylko synchroniczne odczyty i zapisy (na przykład Json.NET):
Ostrzeżenie
Jeśli żądanie jest duże, może to prowadzić do braku pamięci (OOM). OOM może spowodować odmowę usługi. Aby uzyskać więcej informacji, zobacz Unikanie odczytywania dużych treści żądań lub treści odpowiedzi w pamięci w tym artykule.
program ASP.NET Core 3.0 domyślnie używa System.Text.Json serializacji JSON. System.Text.Json:
Newtonsoft.Json
.Obiekt IHttpContextAccessor.HttpContext zwraca HttpContext
aktywne żądanie po korzystaniu z wątku żądania. Element IHttpContextAccessor.HttpContext
nie powinien być przechowywany w polu ani zmiennej.
Nie należy tego robić: poniższy przykład przechowuje HttpContext
element w polu, a następnie próbuje go użyć później.
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");
}
}
}
Powyższy kod często przechwytuje wartość null lub niepoprawną HttpContext
w konstruktorze.
Wykonaj następujące czynności: Poniższy przykład:
HttpContext
Używa pola w odpowiednim czasie i sprawdza element 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
nie jest bezpieczny wątkowo. Dostęp HttpContext
z wielu wątków równolegle może spowodować nieoczekiwane zachowanie, takie jak serwer, aby przestać odpowiadać, ulegać awarii i uszkodzeń danych.
Nie należy tego robić: Poniższy przykład wykonuje trzy żądania równoległe i rejestruje ścieżkę żądania przychodzącego przed i po wychodzącym żądaniu HTTP. Ścieżka żądania jest uzyskiwana z wielu wątków, potencjalnie równolegle.
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;
}
Zrób to: Poniższy przykład kopiuje wszystkie dane z żądania przychodzącego przed wykonaniem trzech żądań równoległych.
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
jest prawidłowy tylko tak długo, jak istnieje aktywne żądanie HTTP w potoku ASP.NET Core. Cały potok ASP.NET Core jest asynchronicznym łańcuchem delegatów, który wykonuje każde żądanie. Po zakończeniu Task
powrotu HttpContext
z tego łańcucha element jest odzyskiwane.
Nie należy tego robić: W poniższym przykładzie użyto async void
metody , która sprawia, że żądanie HTTP zostało ukończone po osiągnięciu pierwszego await
żądania:
async void
zawsze jestzłym rozwiązaniem w aplikacjach ASP.NET Core.HttpResponse
dostęp do obiektu po zakończeniu żądania HTTP.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");
}
}
Wykonaj następujące czynności: poniższy przykład zwraca element Task
do platformy, więc żądanie HTTP nie zostanie ukończone, dopóki akcja nie zostanie ukończona.
public class AsyncGoodTaskController : Controller
{
[HttpGet("/async")]
public async Task Get()
{
await Task.Delay(1000);
await Response.WriteAsync("Hello World");
}
}
Nie należy tego robić: W poniższym przykładzie pokazano, że zamknięcie przechwytuje element HttpContext
z Controller
właściwości . Jest to zła praktyka, ponieważ element roboczy może:
HttpContext
element .[HttpGet("/fire-and-forget-1")]
public IActionResult BadFireAndForget()
{
_ = Task.Run(async () =>
{
await Task.Delay(1000);
var path = HttpContext.Request.Path;
Log(path);
});
return Accepted();
}
Wykonaj następujące czynności: Poniższy przykład:
[HttpGet("/fire-and-forget-3")]
public IActionResult GoodFireAndForget()
{
string path = HttpContext.Request.Path;
_ = Task.Run(async () =>
{
await Task.Delay(1000);
Log(path);
});
return Accepted();
}
Zadania w tle powinny być implementowane jako hostowane usługi. Aby uzyskać więcej informacji, zobacz Zadania w tle z hostowanymi usługami.
Nie należy tego robić: W poniższym przykładzie pokazano zamknięcie przechwytujące DbContext
element z parametru Controller
akcji. Jest to zła praktyka. Element roboczy może działać poza zakresem żądania. Element ContosoDbContext
jest w zakresie żądania, co powoduje ObjectDisposedException
wystąpienie .
[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();
}
Wykonaj następujące czynności: Poniższy przykład:
IServiceScopeFactory
jest singleton.ContosoDbContext
elementu z żądania przychodzącego.[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();
}
Następujący wyróżniony kod:
ContosoDbContext
z prawidłowego zakresu.[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 nie buforuje treści odpowiedzi HTTP. Przy pierwszym zapisaniu odpowiedzi:
Nie należy tego robić: Poniższy kod próbuje dodać nagłówki odpowiedzi po uruchomieniu odpowiedzi:
app.Use(async (context, next) =>
{
await next();
context.Response.Headers["test"] = "test value";
});
W poprzednim kodzie zostanie zgłoszony wyjątek, context.Response.Headers["test"] = "test value";
jeśli next()
został zapisany w odpowiedzi.
Wykonaj to: Poniższy przykład sprawdza, czy odpowiedź HTTP została uruchomiona przed zmodyfikowanie nagłówków.
app.Use(async (context, next) =>
{
await next();
if (!context.Response.HasStarted)
{
context.Response.Headers["test"] = "test value";
}
});
Wykonaj to: W poniższym przykładzie użyto HttpResponse.OnStarting
polecenia , aby ustawić nagłówki przed opróżnieniu nagłówków odpowiedzi do klienta.
Sprawdzanie, czy odpowiedź nie została uruchomiona, umożliwia zarejestrowanie wywołania zwrotnego, które zostanie wywołane tuż przed zapisaniem nagłówków odpowiedzi. Sprawdzanie, czy odpowiedź nie została uruchomiona:
app.Use(async (context, next) =>
{
context.Response.OnStarting(() =>
{
context.Response.Headers["someheader"] = "somevalue";
return Task.CompletedTask;
});
await next();
});
Składniki oczekują wywołania tylko wtedy, gdy będzie można obsługiwać odpowiedź i manipulować nią.
W przypadku hostingu wewnątrz procesu aplikacja ASP.NET Core jest uruchamiana w tym samym procesie, co powiązany proces roboczy usług IIS. Hosting w procesie zapewnia lepszą wydajność hostingu poza procesem, ponieważ żądania nie są oparte na adapterze sprzężenia zwrotnego. Karta sprzężenia zwrotnego to interfejs sieciowy, który zwraca wychodzący ruch sieciowy z powrotem do tej samej maszyny. Usługi IIS obsługują zarządzanie procesami za pomocą usługi aktywacji procesów systemu Windows (WAS).
Projekty domyślne dla modelu hostingu w procesie w programie ASP.NET Core 3.0 lub nowszym.
Aby uzyskać więcej informacji, zobacz Host ASP.NET Core w systemie Windows z usługami IIS
HttpRequest.ContentLength
ma wartość null, jeśli Content-Length
nagłówek nie zostanie odebrany. Wartość null w takim przypadku oznacza, że długość treści żądania nie jest znana; nie oznacza to, że długość wynosi zero. Ponieważ wszystkie porównania z wartością null (z wyjątkiem ==
) zwracają wartość false, porównanie Request.ContentLength > 1024
może na przykład zwracać false
, gdy rozmiar treści żądania jest większy niż 1024. Nie wiedząc, że może to prowadzić do luk w zabezpieczeniach w aplikacjach. Możesz pomyśleć, że chronisz się przed zbyt dużymi żądaniami, gdy nie jesteś.
Aby uzyskać więcej informacji, zobacz tę odpowiedź stackOverflow.
Aby uzyskać wskazówki dotyczące tworzenia niezawodnej, bezpiecznej, wydajnej, testowalnej i skalowalnej aplikacji ASP.NET Core, zobacz wzorce aplikacji internetowych Enterprise. Dostępna jest kompletna przykładowa aplikacja internetowa jakości produkcyjnej, która implementuje wzorce.
Opinia o produkcie ASP.NET Core
ASP.NET Core to projekt typu open source. Wybierz link, aby przekazać opinię:
Zdarzenia
Power BI DataViz World Championships
14 lut, 16 - 31 mar, 16
Z 4 szans na wejście, można wygrać pakiet konferencji i zrobić go do LIVE Grand Finale w Las Vegas
Dowiedz się więcejSzkolenie
Ścieżka szkoleniowa
Use advance techniques in canvas apps to perform custom updates and optimization - Training
Use advance techniques in canvas apps to perform custom updates and optimization
Certyfikacja
Certyfikat firmy Microsoft: Azure Developer Associate - Certifications
Twórz kompleksowe rozwiązania na platformie Microsoft Azure, aby tworzyć usługi Azure Functions, implementować aplikacje internetowe i zarządzać nimi, opracowywać rozwiązania korzystające z usługi Azure Storage i nie tylko.
Dokumentacja
Linki do artykułów dotyczących wydajności w aplikacjach ASP.NET Core.
Oprogramowanie pośredniczące platformy ASP.NET Core
Dowiedz się więcej o potoku żądań i oprogramowaniu pośredniczącym platformy ASP.NET Core.
Uruchamianie aplikacji na platformie ASP.NET Core
Dowiedz się, jak klasa Startup w programie ASP.NET Core konfiguruje usługi i potok żądania aplikacji.