zoukankan      html  css  js  c++  java
  • 关于在Application_Start中访问Context.Request

    昨天抱怨了一下HttpContext的设计,在Global.asax的Application_Start()中访问Context.Request,会引发“Request is not available in this context”异常(注:程序运行于IIS集成模式)。

    有园友反驳说在Application_Start()中不应该去访问Context.Request。我对这个反驳的理解就是HttpApplication还没启动好,还没开始正式处理请求,你就猴急着访问Request干吗?知道不,这和排队一样,有个先来后到。先有HttpApplication,然后才有Request。

    我后来想想,不对呀!我们发布一个ASP.NET网站时,并没有先接通电源,按一个启动按钮让HttpApplication启动起来,然后打开大门大喊:“HTTP请求们,可以进来了”。

    实际情况是,发布网站之后,至少有一个请求,程序才会启动,才会有HttpApplication。明明是先有Request,才会有HttpApplication。

    而且前一篇文章中,我们的需求是在Application_Start()中获取当前Request的URL,Application_Start是由Request而生,有Request的地方就有URL,这个需求合情合理啊!

    在程序员的世界,我们需要反驳,我们也需要对反驳的反抗。

    于是,今天把IIS应用程序池改为传统(Classic)模式,继续在Application_Start()中访问Context.Request。奇迹出现了!竟然可以正常访问Context.Request,拿到想要的Context.Request.Url.AbsoluteUri。这至少说明了,“在Application_Start()中访问Context.Request”的需求是合理的。如果不合理,那么在传统Classic模式也不应该能访问,否则就是一个自相矛盾的设计。

    写代码不是辩论,找到例子证明自己的观点就行了。解决问题或者找到问题的原因才是王道。

    在前一篇文章中,我们知道罪魁祸首是HttpContext的HideRequestResponse属性,再拿出来示众一下:

    internal bool HideRequestResponse;
    public HttpRequest Request
    {
    get
    {
    if (this.HideRequestResponse)
    {
    throw new HttpException(SR.GetString("Request_not_available"));
    }
    return this._request;
    }
    }

    既然在IIS集成模式下才会出现这个异常,那就是在IIS集成模式下,ASP.NET Runtime将HideRequestResponse设置为了true。我们需要找到ASP.NET Runtime在哪里干了这个“勾当”。这就要借助于.NET世界的侦探新星 —— ILSpy。

    在ILSpy中,选中HttpContext的HideRequestResponse属性,点击“Analyze”,看看谁调用了HideRequestResponse并修改了它的值,然后一个一个去侦查。。。侦查的过程这里就省略了。。。直接看我们的侦查结果,先看下面的ILSpy截图:

    既然我们是在Application_Start方法中调用Context.Request,那我们首先就要知道Application_Start是在哪执行。实际就是上图所示的FireApplicationOnStart()方法,反编译出来的代码如下:

    // System.Web.HttpApplicationFactory
    private void FireApplicationOnStart(HttpContext context)
    {
    if (this._onStartMethod != null)
    {
    HttpApplication specialApplicationInstance = this.GetSpecialApplicationInstance();
    specialApplicationInstance.ProcessSpecialRequest(context, this._onStartMethod,
    this._onStartParamCount, this, EventArgs.Empty, null);
    this.RecycleSpecialApplicationInstance(specialApplicationInstance);
    }
    }

    _onStartMethod就是在Global.asax中定义的Application_Start()方法,从上面的代码中可以看出,_onStartMethod是实际在specialApplicationInstance.ProcessSpecialRequest中被执行的,进入ProcessSpecialRequest看个究竟,代码如下(代码已精简,...表示被省略的代码,重点看红色字体部分):

    // System.Web.HttpApplication
    internal void ProcessSpecialRequest(...)
    {
    this._context = context;
    if (HttpRuntime.UseIntegratedPipeline && this._context != null)
    {
    this._context.HideRequestResponse = true;
    }
    ...
    using (new HttpContextWrapper(context))
    {
    using (new ApplicationImpersonationContext())
    {
    try
    {
    //调用Application_Start()方法
    method.Invoke(...)
    ...
    }
    catch (Exception ex)
    {
    ...
    }
    finally
    {
    ...
    if (HttpRuntime.UseIntegratedPipeline && this._context != null)
    {
    this._context.HideRequestResponse = false;
    }
    this._hideRequestResponse = false;
    ...
    }
    }
    }
    }

    从上面的红色字体部分可以看出,真相就在这里,当运行于IIS集成模式时,HttpRuntime.UseIntegratedPipeline就等于true,然后HttpContext.HideRequestResponse被设置为true,然后执行Application_Start()中的代码,然后就引发“Request is not available in this context”异常。

    这篇文章只是对“Request is not available in this context”问题的进一步探索,找出了问题发生的具体地方。至于为什么微软要这么设计?有没有办法在Application_Start()中获取当前请求的URL?即使不能获取,有没有办法避开这个异常?目前我们不知道答案。

  • 相关阅读:
    移植nand驱动补缺:make mrproper与make clean以及make distclean,find/grep. makefile
    repo使用
    git使用总结
    notepade++使用
    linux内核源代码、配置与编译
    linux内核介绍
    块设备
    PHP和javascript中url编码解码详解
    python中的类方法、静态方法、对象方法
    webpack+vue中安装使用vue-layer弹窗插件
  • 原文地址:https://www.cnblogs.com/dudu/p/Application_Start_Context_Request.html
Copyright © 2011-2022 走看看