HttpContext.HideRequestResponse的内部解决方法是什么? 检测HttpContext.Request是否真的可用?

我们正在迁移应用程序以使用IIS7集成模式。 在设计为在HTTP请求的上下文中工作的库代码中,我们通常使用如下代码:

if (HttpContext.Current != null && HttpContext.Current.Request != null) { // do something with HttpContext.Current.Request } else { // do equivalent thing without HttpContext.. } 

但是在IIS7集成模式下,只要从Application_Start调用此代码,就会检查HttpContext.Current.Request会引发exception。

 protected void Application_Start(object sender, EventArgs e) { SomeLibrary.DoSomethingWithHttpContextCurrentDetection(); } 

结果是:

System.Web.HttpException:请求在此上下文中不可用

如果不将这些调用包装在exception处理程序中并根据是否生成exception采取操作,如何检测请求是否真的可用。

看看Reflector中的HttpContext ,我看到它有一个internal bool HideRequestResponse字段,但它是内部的,所以我只能通过reflection得到它并且它很脆弱。 是否有更正式/批准的方式来确定是否可以调用HttpContext.Request

这篇关于这个主题的博客文章说不使用HttpContext ,但是如何在通用库代码中确定是否可以使用HttpContext

IIS7 Integrated mode: Request is not available in this context exception in Application_Start

我正在使用提到的解决方法,即使用Application_BeginRequestinitialized字段仅初始化一次作为BeginRequest一部分,但必须在每个调用应用程序中完成,而我更喜欢使库代码更健壮并处理这种情况,无论它从何处被调用。

我担心答案是你无法得到你想要的东西 – 微软认为这种情况是一种“例外情况”,所以它会引发exception。

您可以在答案中使用reflection,但是您不希望这样做,因此受到Microsoft提供的API的限制,无论好坏。

如果你决定使用reflection,那么值得注意的是HttpApplication.InitInternal方法,该方法设置了HideRequestResponse标志。

希望有所帮助。 我建议您使用Microsoft Connect提交报告。

我会重构你的代码:

 if (IsRequestAvailable()) { // do something with HttpContext.Current.Request... } else { // do equivalent thing without HttpContext... } public Boolean IsRequestAvailable() { if (HttpContext.Current == null) return false; try { if (HttpContext.Current.Request == null) return false; } catch (System.Web.HttpException ex) { #if DEBUG // Testing exception to a magic string not the best practice but // it works for this demo. if (ex.Message == "Request is not available in this context") return false; throw; #else return false; #endif } return true; } 

你的问题要求不要使用exception处理(我假设出于性能原因),我的回答也是如此。 但是,通过将代码从“If(HttpContext.Current!= null && HttpContext.Current.Request!= null)”更改为“If(IsRequestAvailable())”,您只有一个地方可以在找到时更改代码回答如何不使用exception处理。

您甚至不应该Application_Start 使用Request (或Response),因为应用程序可以在没有请求的情况下启动。 因此,将来,当框架的其他部分停止提供Request对象时,您的应用程序甚至不会运行。

如果你想暂时破解它,可以使用Reflection(如果你有中等信任)或捕获exception(即使你不想)并将结果存储在静态变量中或者可能使用静态HttpContext包装

您也可以使用HttpRuntime.UsingIntegratedPipeline

因此,最好的方法是在初始化时删除类在HttpContext上的依赖性,或者在appstart中不对它们进行初始化。

您在应用程序启动时使用Request的原因是什么? 统计? 或者只是告诉用户他唤醒了应用程序?

编辑代码以更好地解释:

 public static class ContextWrapper { public static HttpRequest Request { get { HttpContext context = HttpContext.Current; if (context == null) return null; if (HttpRuntime.UsingIntegratedPipeline) { try { return context.Request; } catch (HttpException e) { /* Consume or log e*/ return null; } // Do not use message comparison - .NET translates messages for multi-culture environments. } return context.Request; } } } 

在代码中:

 if (ContextWrapper.Request != null) //... 

或者用户控制的更快方式:

 public static class ContextWrapper2 { public static bool IsIis7IntegratedAppStart { get; set; } public static HttpRequest Request { get { if (ContextWrapper2.IsIis7IntegratedAppStart) return null; HttpContext context = HttpContext.Current; if (context == null) return null; return context.Request; } } } 

在app开始:

 protected void Application_Start(object sender, EventArgs e) { yourLibraryNamespace.ContextWrapper2.IsIis7IntegratedAppStart = true; //... yourLibraryNamespace.yourClass.Init(); //... yourLibraryNamespace.ContextWrapper2.IsIis7IntegratedAppStart = false; } 

你可以在你的文档中注意到这种行为,一切都应该很好。 类似AppStart的上下文应该是您获得此类exception的唯一地方。

您还可以在成员上实现IDisposable并在appStart中using语句,因此您不要忘记设置IsIis7IntegratedAppStart = false

我添加了评论,但它会自动隐藏。

我认为从请求中了解您需要的内容更为重要。

例如,您提供的提供解决方法的链接正在查找Request.ApplicationPath

如果这实际上是您正在寻找的(例如,加载web.config与app.config相比),您可以这样做:

  if (HttpRuntime.AppDomainAppId != null) return WebConfigurationManager.OpenWebConfiguration(HttpRuntime.AppDomainAppVirtualPath); else return ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); 

如果这个(或HttpRuntime.ApplicationPath )不是您真正想要的,那么了解您实际需要的Request哪些属性会很有帮助。 也许有更好,更安全的方式到达那里。

我想我有适合你的解决方案。 我维护一个日志库并遇到与您相同的问题。 如果是Web请求,我会从HttpContext中获取一些数据。 但是,根据日志库的使用方式,可能会发生同样的情况。 所以这是我的解决方案。 我的关键修复是检查处理程序是否为空。

 if (System.Web.Hosting.HostingEnvironment.IsHosted && System.Web.HttpContext.Current != null && System.Web.HttpContext.Current.Handler != null && System.Web.HttpContext.Current.Request != null) { //access the Request object here } 

根据您要完成的任务,您可以从System.Web.Hosting.HostingEnvironment获取Web应用程序周围的一些属性和设置。