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

时间:2010-04-09 17:23:58

标签: c# asp.net iis-7

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

if (HttpContext.Current != null &&
    HttpContext.Current.Request != null) {

    // do something with HttpContext.Current.Request

} else {

    // do equivalent thing without HttpContext..

}

但是在IIS7集成模式下,只要从HttpContext.Current.Request调用此代码,Application_Start的检查就会抛出异常。

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

结果:

  

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

我如何检测请求是否真的可用而不将这些调用包装在异常处理程序中,并根据是否生成异常采取措施。

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

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

http://mvolo.com/iis7-integrated-mode-request-is-not-available-in-this-context-exception-in-applicationstart/

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

5 个答案:

答案 0 :(得分:9)

我会将你的代码重构为:

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;
}

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

答案 1 :(得分:5)

我担心答案是你不能得到你想要的东西 - 微软认为这种情况是一种“例外情况”,所以它会引发异常。

您可以使用您在答案中描述的反射,但您不希望因此受到Microsoft提供的API的限制,无论好坏。

如果你决定使用反射,那么note是HttpApplication.InitInternal方法,它设置了HideRequestResponse标志。

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

答案 2 :(得分:4)

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

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

您也可以使用HttpRuntime.UsingIntegratedPipeline

因此,最好的方法是在初始化HttpContext时删除类对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;
        }
    }
}

在应用开始时:

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

您可以在文档中注意到这种行为,一切都应该很好。像AppStart一样的上下文应该是你得到这种例外的唯一地方。

你也可以在一个成员上实现IDisposable并在appStart中使用using语句来使用它,这样你就不会忘记设置IsIis7IntegratedAppStart = false

答案 3 :(得分:1)

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

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应用程序周围的一些属性和设置。

答案 4 :(得分:0)

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

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

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

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

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

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