MVC之前-ASP.NET初始化流程分析1

Asp.net Mvc是当前使用比较多的web框架,也是比较先进的框架。我打算根据自己的实际项目经验以及相关的源码和一些使用Asp.net Mvc的优秀项目(主要是orchard)来说一说自己对于Asp.net Mvc原理的理解和一些实践经验。目前.net的大部分源码都已经开放,这大大方便了我们对Asp.net Mvc的分析,下面就从Http请求进入Mvc框架处理之前的基本流程说起。

由于各IIS版本和工作模式(经典模式、集成模式)的不同,Http请求进入Asp.net的处理通道并不一样,这里不去细究里面的细节,就从创建应用程序域开始:

AppManagerAppDomainFactory分析

注:AppDomainFactory及AppManagerAppDomainFactory类在System.Web.Hosting中实现

在创建Appdomain时会调用IAppDomainFactory接口,该接口的实现如下:

 public sealed class AppDomainFactory : IAppDomainFactory {
        private AppManagerAppDomainFactory _realFactory;
        public AppDomainFactory() {
            _realFactory = new AppManagerAppDomainFactory();
        }
        public Object Create(String module, String typeName, String appId, String appPath,String strUrlOfAppOrigin, int iZone) {
            return _realFactory.Create(appId, appPath);
        }
}

该实现会调用AppManagerAppDomainFactory完成实际的创建过程。

  public sealed class AppManagerAppDomainFactory : IAppManagerAppDomainFactory {
        private ApplicationManager _appManager;
        public AppManagerAppDomainFactory() {
            _appManager = ApplicationManager.GetApplicationManager();
            _appManager.Open();
        }
        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 + "\\";
                }
                ISAPIRuntime isapiRuntime = (ISAPIRuntime)_appManager.CreateObjectInternal(appId, typeof(ISAPIRuntime), appHost,false, null);
                isapiRuntime.StartProcessing();
                return new ObjectHandle(isapiRuntime);
            }
            catch (Exception e) {
                Debug.Trace("internal", "AppDomainFactory::Create failed with " + e.GetType().FullName + ": " + e.Message + "\r\n" + e.StackTrace);
                throw;
            }
        }
  }

代码的主要作用,就是通过ApplicationManager的CreateObjectInternal创建AppDomain,创建HostingEnvironment等,最终获取ISAPIRuntime的实例,然后让非托管代码调用。

ApplicationManager分析

注:ApplicationManager类在System.Web.Hosting中实现

首先看ApplicationManager类中的静态的创建ApplicationManager对象的方法:

public static ApplicationManager GetApplicationManager() {
        if (_theAppManager == null) {
            lock (_applicationManagerStaticLock) {
                if (_theAppManager == null) {
                    if (HostingEnvironment.IsHosted)
                        _theAppManager = HostingEnvironment.GetApplicationManager();
                    if (_theAppManager == null)
                        _theAppManager = new ApplicationManager();
                }
            }
        }
        return _theAppManager;
}

如果HostingEnvironment已经创建则可以直接返回当前HostingEnvironment设置的ApplicationManager,如果没有则创建新的ApplicationManager实例。

然后看ApplicationManager的CreateObjectInternal方法:

internal IRegisteredObject CreateObjectInternal(String appId, Type type, IApplicationHost appHost, bool failIfExists, HostingEnvironmentParameters hostingParameters) {
        if (!typeof(IRegisteredObject).IsAssignableFrom(type))
            throw new ArgumentException(SR.GetString(SR.Not_IRegisteredObject, type.FullName), "type");
        HostingEnvironment env = GetAppDomainWithHostingEnvironment(appId, appHost, hostingParameters);
        ObjectHandle h = env.CreateWellKnownObjectInstance(type.AssemblyQualifiedName, failIfExists);
        return (h != null) ? h.Unwrap() as IRegisteredObject : null;
    }

首先要先取得HostingEnvironment的实例,然后通过该实例的CreateWellKnownObjectInstance方法返回上述Create方法需要的ISAPIRuntime的实例。先来看如何获取HostingEnvironment实例的方法GetAppDomainWithHostingEnvironment。

private HostingEnvironment GetAppDomainWithHostingEnvironment(String appId, IApplicationHost appHost, HostingEnvironmentParameters hostingParameters) {
        LockableAppDomainContext ac = GetLockableAppDomainContext (appId);
        lock (ac) {
            HostingEnvironment env = ac.HostEnv;
            if (env != null) {
                try {
                    env.IsUnloaded();
                }
                catch(AppDomainUnloadedException) {
                    env = null;
                }
            }
            if (env == null) {
                env = CreateAppDomainWithHostingEnvironmentAndReportErrors(appId, appHost, hostingParameters);
                ac.HostEnv = env;
                Interlocked.Increment(ref _accessibleHostingEnvCount);
            }
            return env;
        }
    }

首先会检查字典是否会有已经存在的HostingEnvironment实例,如果有就返回,没有就会创建一个新的并保存到字典中,查看相关代码发现最终会调用ApplicationManager的私有方法CreateAppDomainWithHostingEnvironment创建AppDomain和HostingEnvironment。

  private HostingEnvironment CreateAppDomainWithHostingEnvironment(String appId, IApplicationHost appHost, HostingEnvironmentParameters hostingParameters)
  {
       ……
       appDomain = AppDomain.CreateDomain(domainId,GetDefaultDomainIdentity(),setup);
       ……
       Type hostType = typeof(HostingEnvironment);
       String module = hostType.Module.Assembly.FullName;
       String typeName = hostType.FullName;
       ObjectHandle h = null;
       ……
       try {
           h = Activator.CreateInstance(appDomain, module, typeName);
       }
       ……
       HostingEnvironment env = (h != null) ? h.Unwrap() as HostingEnvironment : null;
       if (env == null)
           throw new SystemException(SR.GetString(SR.Cannot_create_HostEnv));
       IConfigMapPathFactory configMapPathFactory = appHost.GetConfigMapPathFactory();
       if (appDomainStartupConfigurationException == null) {
           env.Initialize(this, appHost, configMapPathFactory, hostingParameters, policyLevel);
       }
       else {
           env.Initialize(this, appHost, configMapPathFactory, hostingParameters, policyLevel, appDomainStartupConfigurationException);
       }
       return env;
}

可以看到代码创建了AppDomain和HostingEnvironment实例,创建HostingEnvironment实例以后,紧接着会调用其Initialize方法来进行初始化,然后返回对象实例。

HostingEnvironment分析

Initialize初始化方法,注意该方法的第一个参数是this,也就是ApplicationManager实例自身,这样会在HostingEnvironment中设置ApplicationManager,因而初始化之后可以通过HostingEnvironment获取ApplicationManager 。Initialize方法调用HttpRuntime的静态方法,进行一些初始化工作(其中会调用BuildManager的InitializeBuildManager方法进行初始化另外一些工作,其中包括编译App_Code目录下所有的.NET源代码)。最后如果HostingEnvironment初始化失败时会设置hostingInitFailed为true。

internal void Initialize(ApplicationManager appManager, IApplicationHost appHost, IConfigMapPathFactory configMapPathFactory, HostingEnvironmentParameters hostingParameters, PolicyLevel policyLevel, Exception appDomainCreationException)
{
    ……
    _appManager = appManager;
    ……
    HttpRuntime.InitializeHostingFeatures(hostingFlags,policyLevel,appDomainCreationException);
    ……
    catch (Exception e) {
        _hostingInitFailed = true;
    }
}

创建HostingEnvironment后,会调用其方法CreateWellKnownObjectInstance创建ISAPIRuntime。创建好ISAPIRuntime实例后初始化工作就完成了第一个阶段,整个过程如下图所示:

时间: 2024-10-05 15:57:50

MVC之前-ASP.NET初始化流程分析1的相关文章

Spring Core Container 源码分析三:Spring Beans 初始化流程分析

前言 本文是笔者所著的 Spring Core Container 源码分析系列之一: 本篇文章主要试图梳理出 Spring Beans 的初始化主流程和相关核心代码逻辑: 本文转载自本人的私人博客,伤神的博客: http://www.shangyang.me/2017/04/01/spring-core-container-sourcecode-analysis-beans-instantiating-process/ 本文为作者的原创作品,转载需注明出处: 源码分析环境搭建 参考 Sprin

Raid1源代码分析--初始化流程

初始化流程代码量比较少,也比较简单.主要是run函数.(我阅读的代码的linux内核版本是2.6.32.61) 四.初始化流程分析 run函数顾名思义,很简单这就是在RAID1开始运行时调用,进行一些初始化的操作.主要是对RAID1中的conf进行初始化.run函数在md.c的do_md_run中被调用.   run函数的具体流程 0.传入参数mddev就是指RAID1所处的MD设备. 1.  定义相关变量. 1.1  定义conf指针,类型为raid1_private_data_s,是raid

ASP.NET MVC学前篇之请求流程

ASP.NET MVC学前篇之请求流程 请求流程描述 对于请求的流程,文章的重点是讲HttpApplication和HttpModule之间的关系,以及一个简单的示例实现.(HttpModule又是MVC框架的入口点) 图1 在请求到达Web服务器过后进入ASP.NET的时候是通过ASP.NET来构造出一个HttpWorkerRequest对象,HttpWorkerRequest是抽象类类型,表示着一些请求处理的信息,然后由ASP.NET中的HttpRuntime类型来调用静态函数Process

SpringBoot启动流程分析(四):IoC容器的初始化过程

SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一):SpringApplication类初始化过程 SpringBoot启动流程分析(二):SpringApplication的run方法 SpringBoot启动流程分析(三):SpringApplication的run方法之prepareContext()方法 SpringBoot启动流程分析(四

SpringMVC源码剖析(三)- DispatcherServlet的初始化流程

在我们第一次学Servlet编程,学Java Web的时候,还没有那么多框架.我们开发一个简单的功能要做的事情很简单,就是继承HttpServlet,根据需要重写一下doGet,doPost方法,跳转到我们定义好的jsp页面.Servlet类编写完之后在web.xml里注册这个Servlet类. 除此之外,没有其他了.我们启动web服务器,在浏览器中输入地址,就可以看到浏览器上输出我们写好的页面.为了更好的理解上面这个过程,你需要学习关于Servlet生命周期的三个阶段,就是所谓的“init-s

JAVAWEB开发之Struts2详解(一)——Struts2框架介绍与快速入门、流程分析与工具配置以及Struts2的配置以及Action和Result的详细使用

Struts2框架介绍 三大框架:是企业主流JavaEE开发的一套架构.Struts2 + Spring + Hibernate 什么是框架?为什么要学习框架? 框架是实现部分功能的代码(半成品),使用框架简化企业级软件开发. Struts2与MVC? Struts是一款优秀的MVC框架 MVC:是一种思想,是一种模式,将软件分为Model模型.View视图.Controller控制器 JAVAEE软件三层架构:web层(表现层).业务逻辑层.数据持久层(Sun提供javaEE开发规范) Jav

【开源】OSharp3.3框架解说系列(7.1):初始化流程概述

本文已同步到系列目录:OSharp快速开发框架解说系列 框架初始化 相对于OSharp 3.0,3.3版本最大的更新,就是从框架级别定义了初始化流程,对初始化功能进行了抽象与封装,不依赖于第三方实现,第三方实现仅作为可替换的服务实现方案存在. 例如,依赖注入功能中,接口与其实现类的映射配置,对象容器的构建,对象的解析获取,都将通过框架定义的API来完成,而Autofac,仅作为这些功能的实现方存在,如果不想使用Autofac,则可以很方便的切换成别的IoC组件. 具体的初始化功能是怎样抽象与定义

Linux系统启动流程分析与关机流程

Linux 系统启动流程分析 Linux系统的启动过程并不是大家想象中的那么复杂,其过程可以分为5个阶段: 内核的引导. 运行 init. 系统初始化. 建立终端. 用户登录系统. init程序的类型: SysV: init, CentOS 5之前, 配置文件: /etc/inittab. Upstart: init,CentOS 6, 配置文件: /etc/inittab, /etc/init/*.conf. Systemd: systemd, CentOS 7,配置文件: /usr/lib/

u-boot启动流程分析(2)_板级(board)部分

转自:http://www.wowotech.net/u-boot/boot_flow_2.html 目录: 1. 前言 2. Generic Board 3. _main 4. global data介绍以及背后的思考 5. 前置的板级初始化操作 6. u-boot的relocation 7. 后置的板级初始化操作 1. 前言 书接上文(u-boot启动流程分析(1)_平台相关部分),本文介绍u-boot启动流程中和具体版型(board)有关的部分,也即board_init_f/board_i