第36篇 Asp.Net源码解析(一)

本文详细解析了ASP.NET中从IIS接收请求到处理完成的全过程,包括AppDomain的创建、ISAPIRuntime的作用、HttpRuntime的工作机制及HttpContext和HttpApplication的实例化过程。

上面两篇文章说了http协议和IIS处理,这次说下当IIS把请求交给Asp.net后的过程。

AppManagerAppDomainFactory

  1. 当IIS把请求交给asp.net时候,如果AppDomain还不存在则创建APPDomain,将AppDomain指派给与请求对应的应用程序,这通过AppManagerAppDomainFactory类中的Create方法实现,代码如下:

        public Object Create(String appId, String appPath) {
           try {
    
               if (appPath[0] == '.') {
                   System.IO.FileInfo file = new System.IO.FileInfo(appPath);
                   appPath = file.FullName;
               }
               if (!StringUtil.StringEndsWith(appPath, '\\')) {
                   appPath = appPath + "\\";
               }
    
               ...
    
               ISAPIApplicationHost appHost = new ISAPIApplicationHost(appId, appPath,false);
               //创建环境,包括编译环境
               ISAPIRuntime isapiRuntime = (ISAPIRuntime)_appManager.CreateObjectInternal(appId, typeof(ISAPIRuntime), appHost,  false, null);
               isapiRuntime.StartProcessing();
    
               return new ObjectHandle(isapiRuntime);
    
           }
           catch (Exception e) {
                 ...
           }
       }   
  2. 创建完成后,非托管代码开始调用 ISAPIRuntime 中ProcessRequest方法(通过COM调用 )

ISAPIRuntime--asp.net入口

  1. 首先看下ISAPIRuntime中的ProcessRequest方法签名

        public int ProcessRequest(IntPtr ecb, int iWRType);
  2. ProcessRequest有两个参数,一个是请求报文的ecb句柄,一个请求的类型,在运行的过程中,ecb首先被再次封装成托管资源的请求报文wr。 把封装好的代码传递给HttpRuntime类中的ProcessRequestNoDemand. 核心代码如下:

        bool useOOP = (iWRType == WORKER_REQUEST_TYPE_OOP);
        wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP);
        wr.Initialize();
    
        // check if app path matches (need to restart app domain?)                
        String wrPath = wr.GetAppPathTranslated();
        String adPath = HttpRuntime.AppDomainAppPathInternal;
    
        if (adPath == null ||
            StringUtil.EqualsIgnoreCase(wrPath, adPath))
        {
    
            HttpRuntime.ProcessRequestNoDemand(wr);
            return 0;
        }
        else
        {
            // need to restart app domain
            HttpRuntime.ShutdownAppDomain(ApplicationShutdownReason.PhysicalApplicationPathChanged,
                                        SR.GetString(SR.Hosting_Phys_Path_Changed,
                                                                            adPath,
                                                                            wrPath));
            return 1;
        }

HttpRuntime

  1. HttpRuntime收到传递过来的HttpWorkerRequest类的实例对象wr,通过调用当前类中的ProcessRequestNow方法,把参数传递给ProcessRequestInternal(ProcessRequestNow的调用了ProcessRequestInternal)。

        internal static void ProcessRequestNoDemand(HttpWorkerRequest wr) {
            RequestQueue rq = _theRuntime._requestQueue;
    
            wr.UpdateInitialCounters();
    
            if (rq != null)  // could be null before first request
                wr = rq.GetRequestToExecute(wr);
    
            if (wr != null) {
                CalculateWaitTimeAndUpdatePerfCounter(wr);
                wr.ResetStartTime();
                ProcessRequestNow(wr);
            }
        }
    
        internal static void ProcessRequestNow(HttpWorkerRequest wr) {
            _theRuntime.ProcessRequestInternal(wr);
        }
  2. 在ProcessRequestInternal中,创建了HttpContext和HttpApplication对象实例,核心代码如下

    
        private void ProcessRequestInternal(HttpWorkerRequest wr) {
    
            ...
    
        // Construct the Context on HttpWorkerRequest, hook everything together
        HttpContext context;
    
        try {
            context = new HttpContext(wr, false /* initResponseWriter */);
        } 
        catch {
            ...
        }
    
        ...
    
        try {
                ...
            // Get application instance
            IHttpHandler app = HttpApplicationFactory.GetApplicationInstance(context);
    
            if (app == null)
                throw new HttpException(SR.GetString(SR.Unable_create_app_object));
    
                ... 
    
            if (app is IHttpAsyncHandler) {
                // asynchronous handler
                IHttpAsyncHandler asyncHandler = (IHttpAsyncHandler)app;
                context.AsyncAppHandler = asyncHandler;
                asyncHandler.BeginProcessRequest(context, _handlerCompletionCallback, context);
            }
            else {
                // synchronous handler
                app.ProcessRequest(context);
                FinishRequest(context.WorkerRequest, context, null);
            }
        }
        catch (Exception e) {
            ...
        }
       }
  3. 在ProcessRequestInternal方法的内部,实现对HttpContext类和HttpApplicationFactory的对象实例的创建,核心代码: 根据上面代码,当获得HttApplication对象后,判断是否是IHttpAsyncHandler类型,如果是则调用BeginProcessRequest方法,此处的if条件是一直成立的,因为HttpApplication实现了IHttpAsyncHandler接口,而ProcessRequest方法的实现也仅仅是抛出了一个异常,笔者觉得此处应该是微软留了一个扩展的地方。

       public class HttpApplication:IComponent,IHttpAsyncHandler, IRequestCompletedNotifier, ISyncContext {
            ...
    
        }
    
       void IHttpHandler.ProcessRequest(HttpContext context) {
                throw new HttpException(SR.GetString(SR.Sync_not_supported));
            }

HttpContext对象

这个对象是一个请求响应的结合体,里面包含了HttpRequest和HttpResponse对象,在构造HttpContext对象时,同时也对HttpRequest和HttpResponse也进行了初始化,代码如下:

   internal HttpContext(HttpWorkerRequest wr, bool initResponseWriter) {
        _wr = wr;
        Init(new HttpRequest(wr, this), new HttpResponse(wr, this));

        if (initResponseWriter)
            _response.InitResponseWriter();

        PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_EXECUTING);
    }

创建HttpApplication

通过HttpApplicationFactory中的静态方法GetApplicationInstance来获得实例对象(常用的工厂模式),在创建对象的时候调用了 _theApplicationFactory.GetNormalApplicationInstance(context);方法(其中context形参是上文创建的HttpContext)来执行实例化操作,核心代码如下:


  internal static IHttpHandler GetApplicationInstance(HttpContext context) {
       if (_customApplication != null)
           return _customApplication;

       // Check to see if it's a debug auto-attach request
       if (context.Request.IsDebuggingRequest)
           return new HttpDebugHandler();
       
       _theApplicationFactory.EnsureInited();

       _theApplicationFactory.EnsureAppStartCalled(context);

       return _theApplicationFactory.GetNormalApplicationInstance(context);
   }
        

这个方法里有三个方法的调用,分别是:

i. _theApplicationFactory.EnsureInited()

主要功能是对Global.asxc文件进行编译和处理,并反射出对其中的事件,放到ArrayList中,核心代码如下:

  • 找到global.asax路径进行编译

     private void Init() {
           if (_customApplication != null)
                   return;
               try {
                   try {
                       _appFilename = GetApplicationFile();
                       CompileApplication();
                   }
                   finally {
                       SetupChangesMonitor();
                   }
               }
               catch { 
                   throw;
               }
      }
  • 调用ReflectOnApplicationType方法把事件装入ArrayList

   private void CompileApplication() {
           _theApplicationType = BuildManager.GetGlobalAsaxType();
            BuildResultCompiledGlobalAsaxType result = BuildManager.GetGlobalAsaxBuildResult();
            if (result != null) {
                if (result.HasAppOrSessionObjects) {
                    GetAppStateByParsingGlobalAsax();
                }
                _fileDependencies = result.VirtualPathDependencies;
            }

            if (_state == null) {
                _state = new HttpApplicationState();
            }
            ReflectOnApplicationType();
        }
             
                  
     
 
   private void ReflectOnApplicationType() {
        ArrayList handlers = new ArrayList();
        MethodInfo[] methods;
        // get this class methods
        methods = _theApplicationType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
        foreach (MethodInfo m in methods) {
            if (ReflectOnMethodInfoIfItLooksLikeEventHandler(m))
                handlers.Add(m);
        }
        Type baseType = _theApplicationType.BaseType;
        if (baseType != null && baseType != typeof(HttpApplication)) {
            methods = baseType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
            foreach (MethodInfo m in methods) {
                if (m.IsPrivate && ReflectOnMethodInfoIfItLooksLikeEventHandler(m))
                    handlers.Add(m);
            }
        }
        _eventHandlerMethods = new MethodInfo[handlers.Count];
        for (int i = 0; i < _eventHandlerMethods.Length; i++)
            _eventHandlerMethods[i] = (MethodInfo)handlers[i];
    }
ii. _theApplicationFactory.EnsureAppStartCalled(context)

创建特定的HttpApplication实例,触发ApplicationOnStart事件,执行ASP.global_asax中的Application_Start(object sender, EventArgs e)方法。这里创建的HttpApplication实例在处理完事件后,就被回收。 具体实现:

private void EnsureAppStartCalled(HttpContext context) {
 if (!_appOnStartCalled) {
     lock (this) {
       if (!_appOnStartCalled) {
          using (new DisposableHttpContextWrapper(context)) {
               // impersonation could be required (UNC share or app credentials)

               WebBaseEvent.RaiseSystemEvent(this, WebEventCodes.ApplicationStart);

               // fire outside of impersonation as HttpApplication logic takes
               // care of impersonation by itself
               FireApplicationOnStart(context);
           }
           _appOnStartCalled = true;
        }
     }
   }
 }  
iii. _theApplicationFactory.GetNormalApplicationInstance(context);

主要是获得HttpApplication实例,首先从队列中去取,如果取出为空,则利用反射创建,调用InitInternal方法

 private HttpApplication GetNormalApplicationInstance(HttpContext context) {
         HttpApplication app = null;
         lock (_freeList) {
             if (_numFreeAppInstances > 0) {
                 app = (HttpApplication)_freeList.Pop();
                 _numFreeAppInstances--;

                 if (_numFreeAppInstances < _minFreeAppInstances) {
                     _minFreeAppInstances = _numFreeAppInstances;
                 }
             }
         }
         if (app == null) {
             // If ran out of instances, create a new one
             app = (HttpApplication)HttpRuntime.CreateNonPublicInstance(_theApplicationType);
             using (new ApplicationImpersonationContext()) {
                // 调用BuildSteps和获得所有的HttpModule
                 app.InitInternal(context, _state, _eventHandlerMethods);
             }
         }
         if (AppSettings.UseTaskFriendlySynchronizationContext) {
             // When this HttpApplication instance is no longer in use, recycle it.
             app.ApplicationInstanceConsumersCounter = new CountdownTask(1); // representing required call to HttpApplication.ReleaseAppInstance
             app.ApplicationInstanceConsumersCounter.Task.ContinueWith((_, o) => RecycleApplicationInstance((HttpApplication)o), app, TaskContinuationOptions.ExecuteSynchronously);
         }
         return app;
     }

从代码中可以分析到,在HttpApplication创建的过程中,是有一个_freeList的一个堆栈来控制的。当对象创建成功后,执行app.InitInternal(context, _state, _eventHandlerMethods)来进行后续的操作。整个的代码流程,可以理解成以下过程:

源码git地址:https://github.com/fuwei199006/Source/tree/master/dotnet46/Source

写于 2017.03.07

ASP.NET源码包合集6: [博客空间]FcDigg 0.1 Beta_fcdigg.rar [博客空间]FDW.S BLOG源码_myblogs.rar [博客空间]Finesl v1.7.4.50 SP1_finesl.rar [博客空间]FJBLOG博客系统(.Net开源博客系统)_fjblog.rar [博客空间]Hubro Blogv1.0_hubroblog10.rar [博客空间]I-Favourite 3.0 WAP版_wap2.rar [博客空间]IdioBlog(NClay)源码_idioblog.rar [博客空间]IronRuby博客中文版 Alpha_ironruby-pre-alpha1.rar [博客空间]iShuo多用户博客 v1.5_ishuo1.5.rar [博客空间]LalaBlog 2006 v9_lalablog.rar [博客空间]LevenBlog 2.0.8 源码版_levenblogsor.rar [博客空间]LevenBlog 2.0.8_levenblog.rar [博客空间]LiteWiki 0.2.1_litewiki.rar [博客空间]LiveBlog v1.0 测试版_liveblog.rar [博客空间]mBlog个人博客系统 v1.0 Beta2_mblog.rar [博客空间]myblog v1.2 Access版_myblog12a.rar [博客空间]myblog v1.2 SQL版_myblog12s.rar [博客空间]MySite个人展示程序_mysite_blog.rar [博客空间]NClay框架的博客源码_idio_blog.rar [博客空间]Oblog 4.0(ASP.NET非官方版)_oblog4aspx.rar [博客空间]PersonalBlog个人博客源码_personalblog.rar [博客空间]Presstopia Blog v1.0_ptblog.rar [博客空间]Q-Space 晴网个人空间系统 v2.0 Build 20080820 源代码_qspace2.0_src.rar [博客空间]Q-Space 晴网个人空间系统 v2.0 Build 20080820_qspace2.0.rar [博客空间]Roclog 3.2.15 正式版_roclogpub.rar [博客空间]Roclog 4.1.1 正式版_roclog4.rar [博客空间]ScrewTurn Wiki 2.0.37_screwturnwiki.rar [博客空间]Shang Blog v1.1.0 源码版_shangblog_src.rar [博客空间]Shang-Blog v1.0 SP1 ACC版_shang-blogacc.rar [博客空间]Shang-Blog v1.0 SP1 SQl版_shang-blog.rar [博客空间]shenzheBLOG_sblog.rar [博客空间]Solog v1.0(含C#源码)_solog.rar [博客空间]STStudio简单Blog源码_stblog.rar [博客空间]Subtext v1.9.5英文版_subtext-1.9.5.rar [博客空间]SZBlogsAT 深博问测系统存储过程版 v1.0 Build 0415_szblogsat.rar [博客空间]TriptychBlog v.9.0.6 Source_triptychblog_v.9.0.6[src].rar [博客空间]TriptychBlog博客系统 v.9.0.6 汉化版_triptychblog_access.rar [博客空间]wiki.net(网络维基)源码 v1.1_refylwiki.rar [博客空间]WLQ博客系统源码_wlqblog.rar [博客空间]WSBLog v1.6 Beta 2 Build 70325_wsblog.rar
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值