如何在 ASP.NET MVC 1中从 HttpContextBase 获取 HttpContext 对象?

我正在使用一些与 WebForms/MVC 无关的工具,我需要得到一个 HttpContext实例,它给出了对 HttpContextBase对象的引用。我不能使用 HttpContext.Current,因为我也需要它异步工作(HttpContext.Current在异步请求期间返回 null)。我知道 HttpContextWrapper,但走错了方向。

73909 次浏览

你不能。

HttpContextBase的全部用途是抽象出对具体 HttpContext类的依赖关系。虽然它包含一个具体的 HttpContext (例如 httpContextWrapper的情况),其他实现可能与 HttpContext完全没有关系。

您最好的选择是定义一个定制的抽象工厂,它可以为您获得一个 HttpContextBase,因为您总是可以在 HttpContextWrapper中包装一个具体的 HttpContext

你可以,

var abstractContext = new System.Web.HttpContextWrapper(System.Web.HttpContext.Current);

最简单的方法是获取应用程序 ApplicationInstance并使用其 Context属性:

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

(感谢 以实玛利 · 史麦诺在评论中提到这一点)

原答案:

可以这样做,特别是如果在运行时交给您的 HttpContextBase实例的类型为 HttpContextWrapper。下面的示例说明如何做到这一点。它假设您有一个名为 Foo的方法,该方法接受上下文为 HttpContextBase,但随后需要调用第三方程序集中的一个方法(您可能没有机会修改这个方法) ,该方法希望上下文类型为 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) { /* ... */ }

由于支持 IServiceProvider1,HttpContextBase有一个称为 IServiceProvider0的方法。HttpContextWrapperGetService重写委托给封装的 HttpContext实例的 GetService实现。HttpContextGetService实现允许您查询通常的疑点,如 HttpApplicationGetService0、 GetService1等等。碰巧 HttpApplication有一个名为 IServiceProvider2的属性,它返回 HttpContext的一个实例。因此,可以通过 GetServiceHttpContextBase请求 HttpApplication,然后读取返回的 HttpApplication实例的 GetService8属性,从而获得被包装的 HttpContext实例。

HttpContextBase不同,GetService不以 HttpContext的公共成员的形式出现,但这是因为 HttpContext实现了 IServiceProvider.GetService的显式性,而 HttpContextBase不实现。

请记住,Foo不再是可测试的,因为它依赖于能够在测试期间展开底层的 HttpContext,而这几乎是不可能伪造/存根摆在首位。然而,这个答案的关键在于回答这个问题,“如何从 HttpContextBase 获取 HttpContext 对象?”,真的.在那些你发现自己夹在两个组件之间的情况下,说明技术是有用的,你不一定有豪华的修改。