Beklemeden sonra neden HttpContext.Current null?


91

Aşağıdaki test WebAPI koduna sahibim, üretimde WebAPI kullanmıyorum ancak bunu bu soru üzerine yaptığım bir tartışma nedeniyle yaptım: WebAPI Async sorusu

Her neyse, sorun teşkil eden WebAPI yöntemi şöyledir:

public async Task<string> Get(int id)
{
    var x = HttpContext.Current;
    if (x == null)
    {
        // not thrown
        throw new ArgumentException("HttpContext.Current is null");
    }

    await Task.Run(() => { Task.Delay(500); id = 3; });

    x = HttpContext.Current;
    if (x == null)
    {
        // thrown
        throw new ArgumentException("HttpContext.Current is null");
    }

    return "value";
}

Burada ikinci istisnanın beklendiğine inanmıştım çünkü await tamamlandığında, muhtemelen farklı bir iş parçacığı üzerinde olacak,HttpContext.Current bir iş parçacığı statik değişkeni artık uygun değere çözümlenmeyecek. Şimdi, senkronizasyon bağlamına bağlı olarak, beklemeden sonra aynı iş parçacığına geri dönmek zorunda kalabilir, ancak testimde süslü bir şey yapmıyorum. Bu sadece basit, saf bir kullanım await.

Başka bir sorudaki yorumlarda, HttpContext.Currentbir beklemeden sonra çözülmesi gerektiği söylendi . Bu soru hakkında aynı şeyi belirten başka bir yorum daha var. Peki doğru olan ne? Çözülmeli mi? Hiçbir düşünüyorum, ama bunun nedeni bir yetkili cevap istiyorum asyncve awaitben kesin bir şey bulamıyorum bu yeni yeterlidir.

TL; DR: HttpContext.CurrentPotansiyel olarak nullbir await?


3
Sorunuz belirsizdir - Size ne olmasını beklediğinizi söylediniz, ve yorumlar bu olduğunu göstermektedir olduğunu ne oluyor ... yani aklını karıştırıyor ne?
Jon Skeet

@ user2674389, bu yanıltıcıdır. Bu AspNetSynchronizationContextilgilenir HttpContext, değil await. Dahası, awaitmay için devam geri araması (ve büyük olasılıkla) Web API yürütme modeli için farklı bir iş parçacığında gerçekleşir.
noseratio

kısa ve öz bir soru sormak için düzenlendi
welegan

1
@JoepBeusenberg Yalnızca belirli bir web yığınının HTTP isteği bağlamında çalıştırılan bir derlemeden çağrıldıklarında çalışan ayrı derlemeler oluşturmak, test, bakım ve yeniden kullanım gibi görünüyor.
Darrel Miller

1
@DarrelMiller Tam tersine. İş mantığını gerçek web projesinden ayırdım. Bağımlılık enjeksiyonu kullanarak iş mantığının üstüne webapi-duyarlı bir kitaplık ekleyebilirim. Ancak bu kütüphane, iş mantığı .ConfigureAwait(false)çizginin aşağısında bir yerde olduğunda bozulur . İş katmanı aracılığıyla açıkça iletilen hiçbir istek veya denetleyici yoktur, çünkü bu, web uyumlu değildir. Bu, örneğin, iş mantığı bir genel yazarken istek ayrıntılarını enjekte edebilen bir günlük kaydı modülü için kullanışlıdır TraceInformation.
Joep Beusenberg

Yanıtlar:


150

Lütfen bir ASP.NET 4.5 uygulaması yazdığınızdan ve 4.5'i hedeflediğinizden emin olun . asyncve awaitsen 4,5 üzerinde çalışan sürece ASP.NET üzerinde tanımsız davranışa sahip ve yeni "görev dostu" senkronizasyon bağlamını kullanıyor.

Bu, özellikle şunlardan birini yapmanız gerektiği anlamına gelir:

  • Set httpRuntime.targetFrameworkiçin 4.5veya
  • Gözlerinde farklı appSettings, set aspnet:UseTaskFriendlySynchronizationContextiçin true.

Daha fazla bilgi burada mevcuttur .


2
Yeni bir ASP.NET 4.5 WebAPI projesi oluşturdum, kodunuzu kopyaladım / yapıştırdım ve bir test yaptım. Benim için mükemmel çalıştı (hiçbir istisna atılmadı). Lütfen 4.5 üzerinde çalıştığınızı ve hedeflediğinizi tekrar kontrol edin .
Stephen Cleary

3
Hedef çerçevem ​​var: .NET Framework 4.5 set. Size ne söyleyeceğimi bilmiyorum, yerel makinemde kesinlikle geçersiz.
welegan

24
bu <httpRuntime targetFramework="4.5" />sorunu çözdü, açıkladığınız için teşekkürler.
welegan

1
@ Vince: 4.5.1 iyi çalışmalı. targetFramework4.5.1'e veya 4.5'e ayarlamanız gerekip gerekmediğinden emin değilim , ancak 4.5.1'de zaman uyumsuz olması iyi çalışacaktır.
Stephen Cleary

1
Ya kendi yönetilen işleyicinizi yazdıysanız? Bu öğeleri web.config dosyasına ekledikten sonra bile HttpContext.Current = null ile gelmeye devam ediyorum.
Brain2000

30

@StephenCleary'nin doğru bir şekilde işaret ettiği gibi, web.config'inizde buna ihtiyacınız var:

<httpRuntime targetFramework="4.5" />

Bunu ilk kez sorun giderirken, yukarıdakiler için çözüm çapında bir araştırma yaptım, tüm web projelerimde mevcut olduğunu doğruladım ve suçlu olarak çabucak reddettim. Sonunda bu arama sonuçlarına tam bağlamda bakmak aklıma geldi:

<!--
  For a description of web.config changes for .NET 4.5 see http://go.microsoft.com/fwlink/?LinkId=235367.

  The following attributes can be set on the <httpRuntime> tag.
    <system.Web>
      <httpRuntime targetFramework="4.5" />
    </system.Web>
-->

Doh.

Ders: Bir web projesini 4.5'e yükseltirseniz, yine de bu ayarı manuel olarak yerine getirmeniz gerekir.


22
Başka bir sorun da bu <compilation targetFramework "4.5" /> 'den farklı
Andrew

3

Testim hatalı mı, yoksa burada eksik olduğum ve bir bekleme sonrasında HttpContext.Current çözümünün doğru şekilde çözülmesini sağlayacak bazı web.config öğesi var mı?

Testiniz kusurlu değildir ve beklemeden sonra HttpContext.Current null olmamalıdır, çünkü ASP.NET Web API'de beklediğinizde, bu, beklemeden önce mevcut olan doğru HttpContext'in geçmesini sağlar.


WebAPI için aynı devam iş parçacığından emin misiniz? Ben ele durumda farklı bir iş parçacığı oldu.
noseratio

4
ASP.NET, herhangi bir iş parçacığı havuzu iş parçacığında, ancak doğru istek bağlamıyla devam edecektir.
Stephen Cleary

2
Evet, haklısınız, iş parçacığı aynı olmayabilir ancak HttpContext.Current, bekleme öncesi ile aynı olacaktır. Sorumu güncelledim.
Darin Dimitrov

4
HttpContext.Current, kodumdaki bir bekleme sonrasında boş ve .net 4.6.1'i hedefliyorum.
Triynko

1
benim için HttpContext.Current bir
bekleme

3

Geçenlerde bu sorunla karşılaştım. Stephen'ın belirttiği gibi, hedef çerçeveyi açıkça belirlememek bu sorunu yaratabilir.

Benim durumumda, Web API'miz 4.6.2 sürümüne taşındı ancak çalışma zamanı hedef çerçevesi hiçbir zaman web yapılandırmasında belirtilmedi, bu nedenle temelde bu <system.web> etiketinde eksikti:

Çalıştırdığınız çerçeve sürümü hakkında şüpheleriniz varsa, bu yardımcı olabilir: Web API yöntemlerinizden herhangi birine aşağıdaki satırı ekleyin ve şu anda hangi türün çalışma zamanında yüklendiğini doğrulamak ve bunun Eski bir uygulama olmadığını doğrulamak için bir kesme noktası ayarlayın:

Bunu görmelisiniz (AspNetSynchronizationContext):

görüntü açıklamasını buraya girin

LegazyAspNetSynchronizationContext yerine (Hedef çerçeveyi eklemeden önce gördüğüm şey buydu):

görüntü açıklamasını buraya girin

Kaynak koduna ( https://referencesource.microsoft.com/#system.web/LegacyAspNetSynchronizationContext.cs ) giderseniz, bu arabirimin Eski uygulamasının eşzamansız destekten yoksun olduğunu göreceksiniz.

görüntü açıklamasını buraya girin

Sorunun kaynağını bulmak için çok zaman harcadım ve Stephen'ın cevabı çok yardımcı oldu. Umarım bu yanıt, sorun hakkında biraz daha bilgi sağlar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.