二、OixteSite项目中Global.asax文件中的Application_Start和Application_End方法
查看OxiteSite项目的Global.asax文件,发现其实现代码在Oxite项目的OxiteApplication类中。在Application_Start方法中对OxiteSite进行了初始化工作。
Application_Start方法具体做了哪些事呢?
一是设置依赖注入容器并将之存入应用程序状态中(HttpApplicationState)
二是根据配置加载模块 Oxite中使用的依赖注入容器为Unity(详见Enterprise Library 4.0以上版本)。
setupContainer方法设置注入容器并返回一个UnityContainer对象,保存为Application["container"]。稍后将仔细分析该方法。
Application["bootStrappersLoaded"]用于标认初始化是否完成。
load()方法调用静态方法Load(HttpContextBase context)。作用是根据配置加载指定模块(Module)。
Application_End方法调用unload()方法。在应用程序结束时,完成某些模块的清理工作。
三、setupContainer方法
预备知识:Unity (IOC/DI)、自定义web.config配置结点
通过setupContainer方法的方法名不难看出是用于设置依赖注入容器的。
在setupContainer方法中,首先定义一个IUnityContainer变量parentContainer: 首先,将几个基础对象注册为单例: parentContainer .RegisterInstance((OxiteConfigurationSection)ConfigurationManager.GetSection("oxite")) .RegisterInstance(new AppSettingsHelper(ConfigurationManager.AppSettings)) .RegisterInstance(RouteTable.Routes) .RegisterInstance(System.Web.Mvc.ModelBinders.Binders) .RegisterInstance(ViewEngines.Engines) .RegisterInstance(HostingEnvironment.VirtualPathProvider);
OxiteConfigurationSection类,自定义配置节点。其定义位与Oxite.Configuration命名空间下。是Oxite中实现模块化的配置文件。配置的结点单独放在OxiteSite项目下的oxite.config文件中。
AppSettingsHelper 类对ConfigurationManager.AppSettings 进行包装, 提供几个读取方法GetInt32、GetString等,用于读取web.config文件中的appSettings节点下的值。其实完全可以将这几个读取方法放入NameValueCollectionExtensions类(Oxite.Extensions命名空间下)。不过后来想了想,这里用AppSettingsHelper命名其实也可以明确该类的目的就是为了操作AppSettings结点。
RouteTable.Routes静态属性返回一个RouteCollection静态对象。RouteCollection类在System.Web.Routing程序集中定义。用于保存URL路由设置。 注入容器的目的是为了单元测试。
ModelBinders.Binders静态属性返回一个ModelBinderDictionary静态对象。用于处理数据绑定相关操作(获取表单、查询数据并转换;生成URL路径)。
ViewEngines.Engines静态属性返回一个ViewEngineCollection静态对象。用于视图引擎方面。
HostingEnvironment.VirtualPathProvider静态属性返回一个VirtualPathProvider静态对象。个人猜测可能会用在自定义ViewEngine中,不过目前Oxite版本中好像还没地方用,注释掉也没地方报错。
RouteTable.Routes、ModelBinders.Binders和ViewEngines.Engines是ASP.NET MVC底层比较基础性的属性或对象。值得花时间单独去学习。
接着,将web.config中的connectionStrings和自定义节点“oxite”(oxite.config文件)下的connectionStrings注册为单件。 foreach (ConnectionStringSettings connectionString in ConfigurationManager.ConnectionStrings) parentContainer.RegisterInstance(connectionString. Name, connectionString.ConnectionString); foreach (ConnectionStringSettings connectionString in parentContainer.Resolve<OxiteConfigurationSection>().ConnectionStrings) parentContainer.RegisterInstance(connectionString. Name, connectionString.ConnectionString);
疑问1:在运行时,站点不重启的情况下,如果oxite结点下的connectionStrings改变后,要怎样才能更新到依赖注入容器?这里的处理似乎欠妥。 后来我到Oxite.codeplex.com去问了,Oxite项目组的ErikPorter说目前得重启站点才行。希望他们尽快修正,不然所谓的模块热插拔会大打折扣。
接着看setupContainer方法: LoadModules类和LoadBackgroundServices类位于Oxite.BootStrapperTasks命名空间。从类命名上看,一个是和加载模块相关的,另一个是和加载后台服务相关的,具体是什么得往后细看了。两者都实现了Oxite.Infrastructure命名空间下的IBootStrapperTask接口。IBootStrapperTask就两个方法:Execute和Clearup。IBootStrapperTask我觉得可以直译为引导程序接口,其实例可以称为引导程序。
在这里我们只需要知道,Modules实例和LoadBackgroundSercies实例分别注册为单件。
接着看setupContainer方法中将一些类型也注册到依赖注入容器中,除了几个自定义生命周期的类型外,其他的都只是简单的映射,这里就不多说了。
在setupContainer结束返回值之前,会将web.config文件中Unity配置结点注册入容器中。如果配置结点和我们硬编码中的设置重复,则会覆盖硬编码中的配置。这一特性非常有用,它允许我们在使用程序的默认配置的同时,又提供了一个接口以供我们替换。详情可以查看相关Unity方面的资料。