Saya memiliki kode WebAPI pengujian berikut, saya tidak menggunakan WebAPI dalam produksi, tetapi saya membuatnya karena diskusi yang saya lakukan tentang pertanyaan ini: Pertanyaan Asinkron WebAPI
Bagaimanapun, inilah metode WebAPI yang melanggar:
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";
}
Saya dengan ini percaya bahwa pengecualian kedua diharapkan karena ketika await
selesai, kemungkinan akan berada di utas yang berbeda dimana HttpContext.Current
variabel utas-statis tidak akan lagi menyelesaikan ke nilai yang sesuai. Sekarang, berdasarkan konteks sinkronisasi, itu sebenarnya bisa dipaksa untuk kembali ke utas yang sama setelah menunggu tetapi saya tidak melakukan sesuatu yang mewah dalam pengujian saya. Ini hanyalah penggunaan yang polos dan naif await
.
Dalam komentar di pertanyaan lain, saya diberi tahu yang HttpContext.Current
harus diselesaikan setelah menunggu. Bahkan ada komentar lain atas pertanyaan ini yang menunjukkan hal yang sama. Jadi apa yang benar? Haruskah itu diselesaikan? Saya pikir tidak, tetapi saya ingin jawaban yang berwibawa tentang ini karena async
dan await
cukup baru sehingga saya tidak dapat menemukan sesuatu yang pasti.
TL; DR: Apakah HttpContext.Current
berpotensi null
setelah await
?
sumber
AspNetSynchronizationContext
yang mengurusHttpContext
, bukanawait
. Lebih lanjut, kelanjutan callback untukawait
may (dan kemungkinan besar akan) terjadi pada thread yang berbeda untuk model eksekusi API Web..ConfigureAwait(false)
suatu tempat. Tidak ada permintaan atau pengontrol yang secara eksplisit diserahkan melalui lapisan bisnis, karena lapisan tersebut tidak sadar web. Ini berguna misalnya untuk modul logging yang dapat memasukkan detail permintaan saat logika bisnis menulis generikTraceInformation
.Jawaban:
Harap pastikan Anda menulis aplikasi ASP.NET 4.5 , dan menargetkan 4.5.
async
danawait
memiliki perilaku yang tidak ditentukan di ASP.NET kecuali jika Anda menjalankan pada 4.5 dan menggunakan konteks sinkronisasi "ramah-tugas" yang baru.Secara khusus, ini berarti Anda harus:
httpRuntime.targetFramework
ke4.5
, atauappSettings
, setelaspnet:UseTaskFriendlySynchronizationContext
ketrue
.Informasi lebih lanjut tersedia di sini .
sumber
<httpRuntime targetFramework="4.5" />
yang memecahkannya, terima kasih telah mengklarifikasi.targetFramework
ke 4.5.1 atau 4.5, tetapi async pada 4.5.1 seharusnya berfungsi dengan baik.Seperti yang ditunjukkan dengan benar oleh @StephenCleary, Anda memerlukan ini di web.config Anda:
<httpRuntime targetFramework="4.5" />
Ketika saya pertama kali memecahkan masalah ini, saya melakukan pencarian luas solusi untuk hal di atas, mengonfirmasi bahwa itu ada di semua proyek web saya dan dengan cepat menolaknya sebagai pelakunya. Akhirnya saya terpikir untuk melihat hasil pencarian tersebut dalam konteks lengkap:
<!-- 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.
Pelajaran: Jika Anda mengupgrade proyek web ke 4.5, Anda masih perlu mengaktifkan pengaturan itu secara manual.
sumber
Pengujian Anda tidak cacat dan HttpContext.Current tidak boleh null setelah menunggu karena di ASP.NET Web API saat Anda menunggu, ini akan memastikan bahwa kode yang mengikuti menunggu ini melewati HttpContext yang benar yang ada sebelum menunggu.
sumber
Saya mengalami masalah ini baru-baru ini. Seperti yang ditunjukkan Stephen, tidak menetapkan kerangka target secara eksplisit dapat menimbulkan masalah ini.
Dalam kasus saya, API Web kami dimigrasi ke versi 4.6.2 tetapi kerangka kerja target waktu proses tidak pernah ditentukan dalam konfigurasi web, jadi pada dasarnya ini hilang di dalam tag <system.web>:
Jika Anda ragu tentang versi framework yang Anda jalankan, ini dapat membantu: Tambahkan baris berikut pada salah satu metode API Web Anda dan setel breakpoint untuk memverifikasi jenis apa yang saat ini dimuat saat runtime dan memverifikasi bahwa itu bukan implementasi Legacy:
Anda harus melihat ini (AspNetSynchronizationContext):
Alih-alih LegazyAspNetSynchronizationContext (Yang saya lihat sebelum menambahkan kerangka target):
Jika Anda membuka kode sumber ( https://referencesource.microsoft.com/#system.web/LegacyAspNetSynchronizationContext.cs ), Anda akan melihat bahwa implementasi Legacy dari antarmuka ini kekurangan dukungan asinkron.
Saya menghabiskan banyak waktu mencoba menemukan sumber masalah dan tanggapan Stephen sangat membantu. Semoga jawaban ini memberikan beberapa informasi lebih lanjut tentang masalah ini.
sumber