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

Sam*_*eff 28 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..

}
Run Code Online (Sandbox Code Playgroud)

但是在IIS7集成模式下,HttpContext.Current.Request每次调用此代码时,检查都会抛出异常Application_Start.

protected void Application_Start(object sender, EventArgs e)
{
    SomeLibrary.DoSomethingWithHttpContextCurrentDetection();
}
Run Code Online (Sandbox Code Playgroud)

结果是:

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

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

看着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_BeginRequest和一个initialized字段只能初始化一次作为其中一部分BeginRequest,但必须在每个调用应用程序中完成,而我更喜欢使库代码更健壮并处理这个情况无论从哪里调用.

Tim*_*phy 10

我会重构你的代码:

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;
}
Run Code Online (Sandbox Code Playgroud)

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

  • 为什么你认为避免异常处理如此重要? (2认同)

Jar*_*dek 5

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

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

你也可以使用HttpRuntime.UsingIntegratedPipeline.

所以最好的方法是在你的类被初始化或不在 appstart 中初始化它们时移除它们对 HttpContext 的依赖。

无论如何,您在应用程序启动中使用 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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在代码中:

if (ContextWrapper.Request != null) //...
Run Code Online (Sandbox Code Playgroud)

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

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

并在应用程序开始:

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

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

您还可以在成员上实现 IDisposable 并在 appStart 中使用它的using语句,这样您就不会忘记设置IsIis7IntegratedAppStart = false.


Kie*_*one 5

我担心答案是你无法得到你想要的东西 - 微软认为这种情况是一种"特殊情况",所以它会引发异常.

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

如果您决定使用反射,则note是HttpApplication.InitInternal设置HideRequestResponse标志的方法.

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