Bagaimana cara mendapatkan objek HttpContext dari HttpContextBase di ASP.NET MVC 1?

155

Saya sedang bekerja dengan beberapa alat WebForms / MVC-agnostik, dan saya perlu mendapatkan contoh dari HttpContextmemberikan referensi ke suatu HttpContextBaseobjek. Saya tidak dapat menggunakan HttpContext.Currentkarena saya membutuhkan ini untuk bekerja secara asinkron juga ( HttpContext.Currentkembali nullselama permintaan asinkron). Saya sadar HttpContextWrapper, tapi salah jalan.

Daniel Schaffer
sumber

Jawaban:

250

Cara paling sederhana adalah mendapatkan aplikasi ApplicationInstance,, dan menggunakan Contextpropertinya:

// httpContextBase is of type HttpContextBase
HttpContext context = httpContextBase.ApplicationInstance.Context;

(Terima kasih kepada Ismail Smyrnow yang mencatat ini di komentar)

Jawaban asli:

Anda dapat melakukannya, terutama jika HttpContextBaseinstance yang Anda terima adalah tipe HttpContextWrappersaat run-time. Contoh berikut menggambarkan bagaimana Anda bisa melakukan ini. Itu mengandaikan Anda memiliki metode yang disebut Fooyang menerima konteks sebagai HttpContextBasetetapi kemudian perlu memanggil metode dalam majelis pihak ketiga (bahwa Anda mungkin tidak memiliki nasib baik untuk dimodifikasi) yang mengharapkan konteks yang akan diketikkan HttpContext.

void Foo(HttpContextBase context) 
{
    var app = (HttpApplication) context.GetService(typeof(HttpApplication));
    ThirdParty.Bar.Baz(app.Context);
}

// Somewhere in assembly and namespace ThirdParty,
// in a class called Bar, there is Baz expecting HttpContext:

static void Baz(HttpContext context) { /* ... */ }

HttpContextBasememiliki metode yang disebut GetServicesebagai hasil dari pendukung IServiceProvider. The GetServiceoverride dari HttpContextWrapperdelegasi ke GetServicepelaksanaan dibungkus HttpContextmisalnya. The GetServicepelaksanaan HttpContextmemungkinkan Anda untuk permintaan untuk tersangka seperti HttpApplication, HttpRequest, HttpResponsedan sebagainya. Kebetulan yang HttpApplicationmemiliki properti yang disebut Konteks dan yang mengembalikan contoh HttpContext. Jadi satu mendapat di dibungkus HttpContextmisalnya dengan meminta HttpContextBaseuntuk HttpApplicationmelalui GetServicediikuti dengan membaca Contextmilik kembali HttpApplicationcontoh.

Tidak seperti HttpContextBase, GetServicetidak muncul sebagai anggota publik HttpContexttetapi itu karena HttpContextmengimplementasikan IServiceProvider.GetServicekejelasan sementara HttpContextBasetidak.

Ingatlah bahwa Footidak lagi dapat diuji karena bergantung pada kemampuan untuk membuka bungkus yang mendasarinya HttpContextselama pengujian dan yang hampir tidak mungkin dipalsukan / rintisan. Inti dari jawaban ini, bagaimanapun, adalah untuk menjawab pertanyaan, "Bagaimana saya mendapatkan objek HttpContext dari HttpContextBase?", Secara harfiah . Teknik yang diilustrasikan berguna dalam situasi-situasi di mana Anda menemukan diri Anda terjepit di antara komponen yang tidak perlu Anda modifikasi.

Atif Aziz
sumber
3
Jawaban yang sangat menarik, hanya menggunakannya sendiri di MVC untuk meneruskan HttpContext dari Filter Kesalahan ke ELMAH untuk login.
Chris Marisic
1
jawaban yang bagus, taruhan yang butuh sedikit penggalian? :)
longhairedsi
jawaban bagus! Saya menggunakannya terutama di Elmah saya ke pengontrol MVC github.com/alexanderbeletsky/elmah.mvc.controller/blob/master/…
Alexander Beletsky
36
Dengan HttpContextBase, tidak bisakah Anda menelepon context.ApplicationInstance.Context?
Ismael Smyrnow
@IshmaelSmyrnow Sial, jangan sampai aku melewatkan itu di antara semua Http*Basevariasi yang dikembalikan oleh HttpContextBase. : P Saya akan memperbarui jawabannya.
Atif Aziz
32

Kamu bisa,

var abstractContext = new System.Web.HttpContextWrapper(System.Web.HttpContext.Current);
Marc Chouteau
sumber
16
-1 ini adalah cara yang salah, ini memberi Anda Basis ketika Anda memiliki Konteks, bukan sebaliknya.
Chris Marisic
14

Kamu tidak bisa

Seluruh tujuan HttpContextBaseadalah untuk menghilangkan ketergantungan pada HttpContextkelas konkret . Meskipun mungkin mengandung beton HttpContext (seperti halnya dengan httpContextWrapper) , implementasi lain mungkin sama sekali tidak ada hubungannya HttpContext.

Pilihan terbaik Anda adalah menentukan Pabrik Abstrak kustom yang bisa mendapatkan HttpContextBaseuntuk Anda, karena Anda selalu dapat membungkus beton HttpContextdalam HttpContextWrapper.

Mark Seemann
sumber
13
Ngomong-ngomong, ini dilakukan dengan mengerikan - Saya mengerti ingin memiliki pengaturan untuk tes unit, dan saya mengerti lapisan abstraksi - tetapi WTH yang harus Anda lakukan ketika Anda ingin menggunakan kelas ASP.NET yang ada yang mengharapkan HttpContext? (seperti msdn.microsoft.com/en-us/library/… )
marq
Yap untuk menguji IHttpHandlerimplementasi Anda akhirnya Anda harus memasukkan sejumlah abstraksi di (pembungkus Respon) hanya untuk tes unit Anda, yang tidak terasa benar tetapi akhirnya menjadi satu-satunya pilihan.
Chris S