ASP.NET Core Performansa Yönelik En İyi Yöntemler
Mike Rousos tarafından
Bu makalede, en iyi performans uygulamalarına yönelik yönergeler ve ASP.NET Core.
Agresif bir şekilde önbelleğe alın
Önbelleğe Alma, bu belgenin çeşitli kısımlarında ele alınmıştır. Daha fazla bilgi için bkz. ASP.NET Core 'de yanıt önbelleğe alma.
Hot code yollarını anlama
Bu belgede, sık kullanılan bir kod yolu, sık çağrılır ve yürütme süresi büyük bir sürenin oluştuğu bir kod yolu olarak tanımlanır. Sıcak kod yolları genellikle uygulama ölçeğini ve performansını sınırlar ve bu belgenin çeşitli kısımlarında ele alınmıştır.
Çağrıları engellemeyi önleme
ASP.NET Core uygulamaları aynı anda birçok isteği işley için tasarlanmalı. Zaman uyumsuz API'ler, engelleme çağrılarını beklemeden küçük bir iş parçacığı havuzunun binlerce eş zamanlı isteği işlemesine olanak sağlar. İş parçacığı, uzun süre çalışan bir zaman uyumlu görevin tamamlandıktan sonra başka bir istekte çalışmasına neden olabilir.
Bu uygulamalarda yaygın ASP.NET Core bir sorun, zaman uyumsuz olan çağrıların engellenmesidir. Birçok zaman uyumlu engelleme çağrısı, İş Parçacığı Havuzu'nın bozulmasına ve yanıt süreleri düşürüldü.
Bunu yapma:
- Task.Wait veya Task.Result çağırarak zaman uyumsuz yürütmeyi engelin.
- Ortak kod yollarında kilitleri alın. ASP.NET Core, kod paralel olarak çalıştıracak şekilde mimarisinin en yüksek olduğu uygulamalardır.
- Task.Run'ı çağır ve hemen bekle. ASP.NET Core normal İş Parçacığı Havuzu iş parçacıklarında zaten uygulama kodu çalıştırır, bu nedenle Task.Run çağrısı yapmak yalnızca fazladan gereksiz İş Parçacığı Havuzu zamanlamasıyla sonuç verir. Zamanlanan kod bir iş parçacığını engellese bile Task.Run bunu engellemez.
Yap:
- Sık sık kod yollarını zaman uyumsuz hale geldi.
- Zaman uyumsuz bir API varsa veri erişimini, I/O'yi ve uzun süre çalışan işlem API'lerini zaman uyumsuz olarak çağırma. Zaman uyumlu bir API'yi zaman uyumsuz yapmak için Task.Run'u kullanma.
- RazorDenetleyici/Sayfa eylemlerini zaman uyumsuz hale ekleyin. Async/await desenlerinden yararlanmak için çağrı yığınının tamamı zaman uyumsuz olur.
İş Parçacığı Havuzuna sık sık eklenen iş parçacıklarını bulmak için PerfViewgibi bir profil işleyici kullanılabilir. Olay, Microsoft-Windows-DotNETRuntime/ThreadPoolWorkerThread/Start iş parçacığı havuzuna eklenen bir iş parçacığını gösterir.
Birden çok küçük sayfada büyük koleksiyonlar dönüş
Bir web sayfası aynı anda büyük miktarlarda veri yüklemez. Nesne koleksiyonunu döndürerek performans sorunlarına neden olup olmadığını göz önünde bulundurabilirsiniz. Tasarımın aşağıdaki kötü sonuçları elde etmek için uygun olup olmadığını belirleme:
- OutOfMemoryException veya yüksek bellek tüketimi
- İş parçacığı havuzu açıkları (üzerinde aşağıdaki açıklamalara IAsyncEnumerable<T> bakın)
- Yavaş yanıt süreleri
- Sık çöp toplama
Önceki senaryoları azaltmak için sayfalama ekleyin. Geliştiriciler, sayfa boyutu ve sayfa dizini parametrelerini kullanarak kısmi sonuç döndüren tasarımı tercih ediyor olmalıdır. Kapsamlı bir sonuç gerektiğinde, sunucu kaynaklarını kilitlemeyi önlemek için sonuç toplularını zaman uyumsuz olarak doldurmak için sayfalama kullanılmalıdır.
Disk belleği ve döndürülen kayıt sayısını sınırlama hakkında daha fazla bilgi için bkz:
İade IEnumerable<T> veya IAsyncEnumerable<T>
Bir IEnumerable<T> eylemden dönüş, seri hale getirici tarafından zaman uyumlu koleksiyon yinelemesine neden olur. Sonuç olarak çağrıların engellenmesi ve iş parçacığı havuzu açıkları olabilir. Zaman uyumlu numaralamadan kaçınmak için, ToListAsync numaralanabilir'i döndürmeden önce kullanın.
3.0 ASP.NET Core başlayarak, zaman uyumsuz olarak IAsyncEnumerable<T> IEnumerable<T> numaralara alternatif olarak kullanılabilir. Daha fazla bilgi için bkz. Denetleyici eylemi dönüş türleri.
Büyük nesne ayırmalarını en aza indirme
.NET Core atık toplayıcısı, bellek ayırmayı ve serbest bırakmayı uygulama ASP.NET Core yönetir. Otomatik çöp toplama genellikle geliştiricilerin belleğin nasıl veya ne zaman serbest bırakılası konusunda endişelenmeye gerek olmadığını ifade etmektir. Ancak, çıkarılmamış nesnelerin temizlenmesi CPU süresi alır, bu nedenle geliştiricilerin nesneleri yoğun kod yollarında en aza indirmesi gerekir. Atık toplama özellikle büyük nesneler (85 >) için pahalıdır. Büyük nesneler büyük nesne yığınında depolanır ve temizlemek için tam bir (nesil 2) çöp toplama gerektirir. Nesil 0 ve 1. nesil koleksiyonlardan farklı olarak, 2. nesil koleksiyonlar uygulama yürütmenin geçici olarak askıya alınması gerektirir. Büyük nesnelerin sık sık tahsisi ve ayırması tutarsız performansa neden olabilir.
Öneriler:
- Sık kullanılan büyük nesneleri önbelleğe almayı göz önünde bulundurabilirsiniz. Önbelleğe Alma nesneleri pahalı ayırmaları önler.
- Büyük dizileri depolamak için ArrayPool <T> kullanarak havuz arabellekleri yapma.
- Sıcak kod yollarda çok sayıda, kısa süreli büyük nesne ayırmayın.
Önceki gibi bellek sorunları, PerfView'da atık toplama (GC) istatistikleri gözden geçirerek ve şunları inceler:
- Atık toplama duraklatma süresi.
- Atık toplamada işlemci sürelerinin yüzde kaçı harcanıyor?
- Nesil 0, 1 ve 2 olan atık toplamaları.
Daha fazla bilgi için bkz. Çöp Toplama ve Performans.
Veri erişimini ve I/O'yi iyileştirme
Veri deposu ve diğer uzak hizmetlerle etkileşimler genellikle bir uygulamanın en yavaş ASP.NET Core olur. İyi performans için verileri verimli bir şekilde okuma ve yazma kritik öneme sahip.
Öneriler:
- Tüm veri erişim API'lerini zaman uyumsuz olarak çağırabilirsiniz.
- Gerekenden fazla veri alma. Yalnızca geçerli HTTP isteği için gerekli olan verileri iade etmek için sorgular yazın.
- Biraz güncel olmayan veriler kabul edilebilirse, veritabanından veya uzak hizmetten alınan sık erişilen verileri önbelleğe almayı göz önünde bulundurabilirsiniz. Senaryoya bağlı olarak MemoryCache veya DistributedCache kullanın. Daha fazla bilgi için bkz. ASP.NET Core 'de yanıt önbelleğe alma.
- Ağ gidiş dönüşlerini en aza indirme. Amaç, gerekli verileri birden fazla çağrı yerine tek bir çağrıda almaktır.
- Salt okunur amaçlarla verilere erişirken Entity Framework Core izleme sorgularını kullanın. EF Core izleme olmayan sorguların sonuçlarını daha verimli bir şekilde geri getiresiniz.
- Filtrelemenin veritabanı tarafından gerçekleştirilecek şekilde LINQ sorgularını (örneğin, , veya deyimleriyle) filtrele
.Where.Selectve.Sumtoplama. - İstemcide bazı EF Core işleçleri çözümleyemezse sorgu yürütmenin verimsiz olduğunu göz önünde bulundurabilirsiniz. Daha fazla bilgi için bkz. İstemci değerlendirme performansı sorunları.
- Koleksiyonlarda yansıtma sorguları kullanmayın; bu da "N + 1" ve "N + 1" sorgularının SQL olabilir. Daha fazla bilgi için, bkz. İyileştirme ilişkili altqueries.
Yüksek ölçekli uygulamalarda performansı geliştirebilir yaklaşımlar için bkz. EF Yüksek Performansı:
Kod tabanını işlemeden önce önceki yüksek performanslı yaklaşımların etkisini ölçmenizi öneririz. Derlenmiş sorguların ek karmaşıklığı, performans geliştirmeyi haklı çıkarmaz.
Sorgu sorunları, Application Analizler veya profil oluşturma araçlarıyla verilere erişim için harcanan süre gözden geçirilir. Çoğu veritabanı, sık yürütülen sorgularla ilgili istatistikler de sağlar.
HttpClientFactory ile HAVUZ HTTP bağlantıları
HttpClient arabirimini IDisposable uygulaysa da, yeniden kullanım için tasarlanmıştır. Kapalı HttpClient örnekler yuvaları kısa TIME_WAIT bir süre için açık durumda bırakır. Nesneleri oluşturan ve atan bir kod HttpClient yolu sık kullanılırsa, uygulama kullanılabilir yuvaları tüketmiş olabilir. httpclientfactory , bu soruna çözüm olarak ASP.NET Core 2,1 ' de tanıtılmıştı. Performansı ve güvenilirliği iyileştirmek için havuz HTTP bağlantılarını işler.
Öneriler:
- Örnekleri doğrudan oluşturma ve atma
HttpClient. - Örnek almak Için httpclientfactory kullanın
HttpClient. Daha fazla bilgi için bkz. Esnek http isteklerini uygulamak Için HttpClientFactory kullanma.
Ortak kod yollarını hızlı tutun
Tüm kodunuzun hızlı olmasını istiyorsunuz. Yaygın olarak çağrılan kod yolları en kritik öneme sahiptir. Bu modüller şunlardır:
- Uygulamanın istek işleme ardışık düzeninde bulunan ara yazılım bileşenleri, özellikle de ara yazılım ardışık düzende çalışır. Bu bileşenlerin performansı üzerinde büyük bir etkisi vardır.
- Her istek için veya istek başına birden çok kez yürütülen kod. Örneğin, özel günlük kaydı, yetkilendirme işleyicileri veya geçici Hizmetleri başlatma.
Öneriler:
- Uzun süre çalışan görevlerle özel ara yazılım bileşenleri kullanmayın.
- etkin kod yollarınıbelirlemek için Visual Studio Tanılama Araçları veya perfviewgibi performans profil oluşturma araçlarını kullanın.
Uzun süre çalışan görevleri http isteklerinin dışında Tamam
ASP.NET Core uygulamasına yönelik çoğu istek, gerekli hizmetleri çağıran ve HTTP yanıtı döndüren bir denetleyici veya sayfa modeli tarafından işlenebilir. Uzun süre çalışan görevleri içeren bazı istekler için, tüm istek-yanıt sürecini zaman uyumsuz hale getirmek daha iyidir.
Öneriler:
- Olağan HTTP istek işlemenin bir parçası olarak uzun süre çalışan görevlerin tamamlanmasını beklememe .
- Arka plan hizmetleri ile uzun süreli istekleri işlemeyi veya bir Azure işleviile işlem dışı bırakmayı düşünün. İşlem dışı iş tamamlama, özellikle CPU yoğun görevler için faydalıdır.
- İstemcilerle zaman uyumsuz iletişim kurmak için gibi gerçek zamanlı iletişim seçenekleri kullanın SignalR .
İstemci varlıklarını küçültmeye yönelik
karmaşık ön uçları olan ASP.NET Core uygulamalar sıklıkla birçok JavaScript, CSS veya görüntü dosyası sunar. İlk yük isteklerinin performansı şu şekilde geliştirilebilir:
- Birden çok dosyayı bir içinde birleştiren paketleme.
- Boşluk ve açıklamaları kaldırarak dosyaların boyutunu azaltan minifying.
Öneriler:
- uyumlu araçlarla bahsetmeyen ve hem hem de ortamları işlemek için ASP.NET Core etiketinin nasıl kullanılacağını gösteren paketleme ve küçültmeye yönelik yönergelerikullanın
environmentDevelopmentProduction. - Karmaşık istemci varlık yönetimi için WebPackgibi diğer üçüncü taraf araçları göz önünde bulundurun.
Yanıtları sıkıştır
Yanıt boyutunu azaltmak genellikle önemli ölçüde önemli ölçüde bir uygulamanın yanıt hızını artırır. Yük boyutlarını azaltmanın bir yolu, uygulamanın yanıtlarını sıkıştırmaktır. Daha fazla bilgi için bkz. Yanıt sıkıştırması.
en son ASP.NET Core sürümü kullan
ASP.NET Core her yeni sürümü performans iyileştirmeleri içerir. .net Core ve ASP.NET Core iyileştirmeler, daha yeni sürümlerin genellikle eski sürümlerin genel olarak gerçekleştirdiği anlamına gelir. Örneğin, .NET Core 2,1, derlenmiş normal ifadeler ve benefitted 'dan gelen <T> destek eklendi. ASP.NET Core 2,2 HTTP/2 desteği eklendi. ASP.NET Core 3,0, bellek kullanımını azaltan ve üretilen işi geliştiren birçok geliştirme ekler . Performans bir önceliktir, ASP.NET Core güncel sürümüne yükseltmeyi göz önünde bulundurun.
Özel durumları Küçült
Özel durumlar nadir olmalıdır. Özel durumları oluşturma ve yakalama, diğer kod akışı desenlerine göre yavaş olur. Bu nedenle, normal program akışını denetlemek için özel durumlar kullanılmamalıdır.
Öneriler:
- Özel durumları, özellikle de sık erişimli kod yollarındanormal program akışının bir yolu olarak oluşturma veya yakalama kullanmayın.
- Özel duruma neden olacak koşulları tespit etmek ve işlemek için uygulamaya mantığı dahil edin .
- Olağan dışı veya beklenmedik koşullarda özel durumlar oluşturun veya yakalayın.
Application Insights gibi uygulama tanılama araçları, bir uygulamadaki performansı etkileyebilecek ortak özel durumları belirlemesine yardımcı olabilir.
Performans ve güvenilirlik
Aşağıdaki bölümlerde performans ipuçları ve bilinen güvenilirlik sorunları ve çözümleri sağlanmaktadır.
HttpRequest/HttpResponse gövdesinde zaman uyumlu okuma veya yazma yapmaktan kaçının
ASP.NET Core tüm g/ç zaman uyumsuzdur. Sunucular Stream , hem zaman uyumlu hem de zaman uyumsuz aşırı yüklemeleri olan arabirimini uygular. İş parçacığı havuzu iş parçacıklarını engellemeyi önlemek için zaman uyumsuz olanlar tercih edilmelidir. İş parçacıklarını engelleme, iş parçacığı havuzunda ortaya çıkmasına neden olabilir.
Bunu yapın: Aşağıdaki örnek öğesini kullanır ReadToEnd . Sonuç için beklemek üzere geçerli iş parçacığını engeller. Bu, zaman uyumsuz olarak eşitlemeörneğidir.
public class BadStreamReaderController : Controller
{
[HttpGet("/contoso")]
public ActionResult<ContosoData> Get()
{
var json = new StreamReader(Request.Body).ReadToEnd();
return JsonSerializer.Deserialize<ContosoData>(json);
}
}
Yukarıdaki kodda, Get http istek gövdesinin tamamını belleğe eşzamanlı olarak okur. İstemci yavaş karşıya yüklendikten sonra, uygulama zaman uyumsuz olarak eşitlenir. Zaman uyumlu okumayı desteklemediği için uygulama zaman uyumsuz olarak eşitlenir Kestrel .
Bunu yapın: Aşağıdaki örnek, ReadToEndAsync okurken iş parçacığını engellemez.
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);
}
}
Yukarıdaki kod, HTTP istek gövdesinin tamamını belleğe zaman uyumsuz olarak okur.
Uyarı
İstek büyükse HTTP istek gövdesinin tamamını belleğe okumak bellek yetersiz (OOM) koşuluna yol açabilir. OOM, hizmet reddine neden olabilir. Daha fazla bilgi için, bu belgedeki büyük istek gövdelerini veya Yanıt gövdelerinin belleğe okunmasını önleyin .
Bunu yapın: Aşağıdaki örnek, arabelleğe alınmamış bir istek gövdesi kullanılarak tamamen zaman uyumsuzdur:
public class GoodStreamReaderController : Controller
{
[HttpGet("/contoso")]
public async Task<ActionResult<ContosoData>> Get()
{
return await JsonSerializer.DeserializeAsync<ContosoData>(Request.Body);
}
}
Yukarıdaki kod, istek gövdesini bir C# nesnesine zaman uyumsuz olarak serileştirir.
Istek üzerinde ReadFormAsync tercih et. form
HttpContext.Request.ReadFormAsyncYerine kullanın HttpContext.Request.Form .
HttpContext.Request.Form yalnızca aşağıdaki koşullara göre güvenle okunabilir:
- Form, bir çağrısıyla okundu
ReadFormAsyncve - Önbelleğe alınan form değeri şu kullanılarak okunmakta
HttpContext.Request.Form
Bunu yapın: Aşağıdaki örnek kullanılmıştır HttpContext.Request.Form . HttpContext.Request.Form , zaman uyumsuz olarak eşitleme kullanır ve iş parçacığı havuzunda ortaya çıkmasına neden olabilir.
public class BadReadController : Controller
{
[HttpPost("/form-body")]
public IActionResult Post()
{
var form = HttpContext.Request.Form;
Process(form["id"], form["name"]);
return Accepted();
}
Bunu yapın: Aşağıdaki örnek, HttpContext.Request.ReadFormAsync form gövdesini zaman uyumsuz olarak okumak için kullanır.
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();
}
Büyük istek gövdelerini veya yanıt gövdelerini belleğe okumaktan kaçının
.NET ' te, 85 KB 'den büyük olan her nesne ayırması büyük nesne yığınında (Loh) sona erer. Büyük nesneler iki şekilde pahalıdır:
- Yeni ayrılan büyük bir nesne için belleğin temizlenmesi gerektiğinden, ayırma maliyeti yüksektir. CLR, tüm yeni ayrılmış nesneler için belleğin temizlenmiş olmasını garanti eder.
- LOH, yığının geri kalanı ile toplanır. LOH, tam atık toplama veya Gen2 koleksiyonugerektirir.
Bu blog gönderisi succinctly sorununu açıklar:
Büyük bir nesne ayrıldığında, Gen 2 nesnesi olarak işaretlenir. Küçük nesneler için Gen 0 değildir. Sonuçlar LOH 'de bellek tükeniyorsa, GC yalnızca LOH değil, yönetilen yığının tamamını temizler. Bu nedenle, LOH dahil olmak üzere Gen 0, Gen 1 ve Gen 2 ' yi temizler. Bu, tam atık toplama olarak adlandırılır ve en çok kullanılan çöp toplamadır. Birçok uygulama için kabul edilebilir. Ancak, ortalama bir web isteğini işlemek için çok büyük bellek arabelleklerinin (bir yuvadan okunan, sıkıştırmayı açık olan JSON & daha fazla kod çözme) gerekli olduğu yüksek performanslı Web sunucuları için kesinlikle değildir.
Büyük bir isteği veya Yanıt gövdesini tek bir veya ' a bir veya daha fazla depolama byte[] string :
- LOH 'de hızlı bir şekilde boş alan tükenmenize neden olabilir.
- Çalıştıran tam GC 'Ler nedeniyle uygulama için performans sorunlarına neden olabilir.
Zaman uyumlu veri işleme API 'SI ile çalışma
Yalnızca zaman uyumlu okuma ve yazma işlemlerini destekleyen bir serileştirici/devre dışı bırakma kullanılırken (örneğin, JSON.net):
- Verileri seri hale getirici/devre dışı serileştiriciye geçirmeden önce zaman uyumsuz olarak belleğe arabelleğe ın.
Uyarı
İstek büyükse, bellek yetersiz (OOM) koşuluna yol açabilir. OOM, hizmet reddine neden olabilir. Daha fazla bilgi için, bu belgedeki büyük istek gövdelerini veya Yanıt gövdelerinin belleğe okunmasını önleyin .
ASP.NET Core 3,0, System.Text.Json JSON serileştirme için varsayılan olarak kullanır. System.Text.Json:
- JSON 'yi zaman uyumsuz olarak okur ve yazar.
- UTF-8 metni için iyileştirilmiştir.
- Genellikle daha yüksek performans
Newtonsoft.Json.
Bir alanda ıhttpcontextaccessor. HttpContext depolamayın
Ihttpcontextaccessor. HttpContext , HttpContext istek iş parçacığından erişildiğinde etkin isteğin ' i döndürür. , IHttpContextAccessor.HttpContext Bir alan veya değişkende depolanmamalıdır.
Bunu yapın: Aşağıdaki örnek HttpContext öğesini bir alanında depolar ve daha sonra kullanmaya çalışır.
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");
}
}
}
Yukarıdaki kod, oluşturucuda genellikle null veya yanlış yakalar HttpContext .
Bunu yapın: Aşağıdaki örnek:
- IHttpContextAccessorAlanını bir alanında depolar.
HttpContextAlanı doğru zamanda kullanır ve kontrol edernull.
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");
}
}
}
Birden çok iş parçacığından HttpContext 'e erişme
HttpContext , iş parçacığı açısından güvenli değildir . HttpContextParalel olarak birden çok iş parçacığından erişilmesi, askıda kalma, kilitlenme ve veri bozulması gibi tanımsız davranışlara neden olabilir.
Bunu yapın: Aşağıdaki örnek üç paralel istek yapar ve giden HTTP isteğinden önce ve sonra gelen istek yolunu günlüğe kaydeder. İstek yoluna, potansiyel olarak paralel olarak birden çok iş parçacığından erişilir.
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;
}
Bunu yapın: Aşağıdaki örnek, üç paralel isteği yapmadan önce gelen istekten tüm verileri kopyalar.
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;
}
İstek tamamlandıktan sonra HttpContext 'i kullanma
HttpContextyalnızca ASP.NET Core işlem hattında etkin bir HTTP isteği olduğu sürece geçerlidir. tüm ASP.NET Core işlem hattı, her isteği yürüten zaman uyumsuz temsilciler zinciridir. TaskBu zincirden döndürülen işlem tamamlandığında, geri dönüştürülür HttpContext .
Bunu yapın: Aşağıdaki örnek, async void ilk kez ULAŞıLDıĞıNDA http isteğinin tamamlanmasını sağlar await :
- ASP.NET Core uygulamalarda bu her zaman hatalı bir uygulamadır.
HttpResponseHttp isteği tamamlandıktan sonra öğesine erişir.- İşlemi çöker.
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");
}
}
Bunu yapın: Aşağıdaki örnek çerçevesine bir döndürür Task , bu nedenle http isteği eylem tamamlanana kadar tamamlanmaz.
public class AsyncGoodTaskController : Controller
{
[HttpGet("/async")]
public async Task Get()
{
await Task.Delay(1000);
await Response.WriteAsync("Hello World");
}
}
Arka plan iş parçacıklarında HttpContext 'i yakalama
Bunu yapın: Aşağıdaki örnekte, bir kapanışın özelliğinden yakalanırken bir kapanış gösterilmektedir HttpContext Controller . Bu kötü bir uygulamadır çünkü iş öğesi şu şekilde olabilir:
- İstek kapsamının dışında çalıştırın.
- Yanlış okuma girişimi
HttpContext.
[HttpGet("/fire-and-forget-1")]
public IActionResult BadFireAndForget()
{
_ = Task.Run(async () =>
{
await Task.Delay(1000);
var path = HttpContext.Request.Path;
Log(path);
});
return Accepted();
}
Bunu yapın: Aşağıdaki örnek:
- İstek sırasında arka plan görevinde gereken verileri kopyalar.
- Denetleyiciden hiçbir şeye başvurmuyor.
[HttpGet("/fire-and-forget-3")]
public IActionResult GoodFireAndForget()
{
string path = HttpContext.Request.Path;
_ = Task.Run(async () =>
{
await Task.Delay(1000);
Log(path);
});
return Accepted();
}
Arka plan görevleri barındırılan hizmet olarak uygulanmalıdır. Daha fazla bilgi için bkz. barındırılan hizmetlerle arka plan görevleri.
Arka plan iş parçacıklarında denetleyicilere eklenen Hizmetleri yakalama
Bunu yapın: Aşağıdaki örnek, bir kapanışın DbContext Controller eylem parametresinden yakalama işlemini gösterir. Bu kötü bir uygulamadır. İş öğesi, istek kapsamı dışında çalıştırılabilir. , ContosoDbContext İstek kapsamına alınır ve buna yol açar ObjectDisposedException .
[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();
}
Bunu yapın: Aşağıdaki örnek:
- IServiceScopeFactoryArka plan iş öğesinde bir kapsam oluşturmak için bir oluşturur.
IServiceScopeFactorytek bir. - Arka plan iş parçacığında yeni bir bağımlılık ekleme kapsamı oluşturur.
- Denetleyiciden hiçbir şeye başvurmuyor.
ContosoDbContextGelen istekten yakalanmaz.
[HttpGet("/fire-and-forget-3")]
public IActionResult FireAndForget3([FromServices]IServiceScopeFactory
serviceScopeFactory)
{
_ = Task.Run(async () =>
{
await Task.Delay(1000);
using (var scope = serviceScopeFactory.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<ContosoDbContext>();
context.Contoso.Add(new Contoso());
await context.SaveChangesAsync();
}
});
return Accepted();
}
Aşağıdaki vurgulanan kod:
- Arka plan işleminin yaşam süresi boyunca bir kapsam oluşturur ve Hizmetleri bundan çözer.
ContosoDbContextDoğru kapsamdan kullanır.
[HttpGet("/fire-and-forget-3")]
public IActionResult FireAndForget3([FromServices]IServiceScopeFactory
serviceScopeFactory)
{
_ = Task.Run(async () =>
{
await Task.Delay(1000);
using (var scope = serviceScopeFactory.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<ContosoDbContext>();
context.Contoso.Add(new Contoso());
await context.SaveChangesAsync();
}
});
return Accepted();
}
Yanıt gövdesi başlatıldıktan sonra durum kodunu veya başlıkları değiştirmeyin
ASP.NET Core HTTP yanıt gövdesini arabelleğe almaz. Yanıtın ilk yazıldığı zaman:
- Üst bilgiler, bu gövdenin öbek ile birlikte gönderilir.
- Artık yanıt üst bilgilerini değiştirmek mümkün değildir.
Bunu yapın: Aşağıdaki kod, yanıt önceden başlatıldıktan sonra yanıt üst bilgileri eklemeye çalışır:
app.Use(async (context, next) =>
{
await next();
context.Response.Headers["test"] = "test value";
});
Önceki kodda, context.Response.Headers["test"] = "test value"; yanıta yazılmışsa bir özel durum oluşturur next() .
Bunu yapın: Aşağıdaki örnek, üst bilgileri değiştirmeden önce HTTP yanıtının başlatılıp başlatılmadığını denetler.
app.Use(async (context, next) =>
{
await next();
if (!context.Response.HasStarted)
{
context.Response.Headers["test"] = "test value";
}
});
Bunu yapın: Aşağıdaki örnek, HttpResponse.OnStarting yanıt üst bilgileri istemciye temizlenmeden önce üst bilgileri ayarlamak için kullanır.
Yanıtın başlatılmamış olup olmadığı denetleniyor yanıt üst bilgileri yazılmadan önce çağrılacak geri aramanın kaydedilmesini sağlar. Yanıtın başlatılmamış olup olmadığı denetleniyor:
- Başlıkları tam zamanında ekleme veya geçersiz kılma olanağı sağlar.
- İşlem hattındaki bir sonraki ara yazılım hakkında bilgi gerektirmez.
app.Use(async (context, next) =>
{
context.Response.OnStarting(() =>
{
context.Response.Headers["someheader"] = "somevalue";
return Task.CompletedTask;
});
await next();
});
Yanıt gövdesine yazmaya başladıysanız ileri () çağrısı yapın
Bileşenler yalnızca yanıtı işlemek ve işlemek için mümkünse çağrılabilir.
IIS ile işlem Içi barındırma kullanma
ASP.NET Core bir uygulama, işlem içi barındırma kullanarak ııs çalışan işlemiyle aynı işlemde çalışır. İşlem içi barındırma, isteklerin geri döngü bağdaştırıcısı üzerinde proxy olmadığından işlem dışı barındırma üzerinde gelişmiş performans sağlar. Geri döngü bağdaştırıcısı, giden ağ trafiğinin aynı makineye geri döndürdüğü bir ağ arabirimidir. ııs, Windows işlem etkinleştirme hizmeti (WAS)ile işlem yönetimini işler.
projeler varsayılan olarak ASP.NET Core 3,0 ve sonraki sürümlerde işlem içi barındırma modeline göre yapılır.
daha fazla bilgi için bkz. ııs ile Windows ana bilgisayar ASP.NET Core