首页 > 代码库 > 你必须知道ASP.NET知识------关于动态注册httpmodule(对不起汤姆大叔)

你必须知道ASP.NET知识------关于动态注册httpmodule(对不起汤姆大叔)

一、关于动态注册的问题

  很多人看过汤姆大叔的MVC之前的那点事儿系列(6):动态注册HttpModule

 ,其实汤姆大叔没有发现httpmodule动态注册的根本机制在哪里.

亦即:怎么动态注册?为什么能够动态注册?

  汤姆大叔给了如下开篇

通过前面的章节,我们知道HttpApplication在初始化的时候会初始化所有配置文件里注册的HttpModules,那么有一个疑问,能否初始化之前动态加载HttpModule,而不是只从Web.config里读取?

答案是肯定的, ASP.NET MVC3发布的时候提供了一个Microsoft.Web.Infrastructure.dll文件,这个文件就是提供了动态注册HttpModule的功能,那么它是如何以注册的呢?我们先去MVC3的源码看看该DLL的源代码。

  其实httpmodule动态注册,是ASP.NET框架内部自己提供的机制,和MVC没有关系,也就是说有没有MVC,ASP.NET自己都会提供这个机制(没有研究其他

.NET版本,至少在.NET 4.0下是如此的,这是不含MVC框架的情况下)

二、关于httpmodule的初始化

接着前面的章节,我们开始论述,以下面的代码回顾

// System.Web.HttpApplicationinternal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers){    this._state = state;    PerfCounters.IncrementCounter(AppPerfCounter.PIPELINES);    try    {        try        {            this._initContext = context;            this._initContext.ApplicationInstance = this;            context.ConfigurationPath = context.Request.ApplicationPathObject;            using (new DisposableHttpContextWrapper(context))            {                if (HttpRuntime.UseIntegratedPipeline)                {                    try                    {                        context.HideRequestResponse = true;                        this._hideRequestResponse = true;                        this.InitIntegratedModules();                        goto IL_6B;                    }                    finally                    {                        context.HideRequestResponse = false;                        this._hideRequestResponse = false;                    }                }                this.InitModules();//注意这里,这里是初始化所有的module,其中包括了配置文件中的和动态注册的                IL_6B:                if (handlers != null)                {                    this.HookupEventHandlersForApplicationAndModules(handlers);                }                this._context = context;                if (HttpRuntime.UseIntegratedPipeline && this._context != null)                {                    this._context.HideRequestResponse = true;                }                this._hideRequestResponse = true;                try                {                    this.Init();                }                catch (Exception error)                {                    this.RecordError(error);                }            }            if (HttpRuntime.UseIntegratedPipeline && this._context != null)            {                this._context.HideRequestResponse = false;            }            this._hideRequestResponse = false;            this._context = null;            this._resumeStepsWaitCallback = new WaitCallback(this.ResumeStepsWaitCallback);            if (HttpRuntime.UseIntegratedPipeline)            {                this._stepManager = new HttpApplication.PipelineStepManager(this);            }            else            {                this._stepManager = new HttpApplication.ApplicationStepManager(this);            }            this._stepManager.BuildSteps(this._resumeStepsWaitCallback);        }        finally        {            this._initInternalCompleted = true;            context.ConfigurationPath = null;            this._initContext.ApplicationInstance = null;            this._initContext = null;        }    }    catch    {        throw;    }}

 

private void InitModules(){    HttpModulesSection httpModules = RuntimeConfig.GetAppConfig().HttpModules;//配置文件中的    HttpModuleCollection httpModuleCollection = httpModules.CreateModules();//动态注册的    HttpModuleCollection other = this.CreateDynamicModules();    httpModuleCollection.AppendCollection(other);    this._moduleCollection = httpModuleCollection;    this.InitModulesCommon();}
private HttpModuleCollection CreateDynamicModules(){    HttpModuleCollection httpModuleCollection = new HttpModuleCollection();    foreach (DynamicModuleRegistryEntry current in HttpApplication._dynamicModuleRegistry.LockAndFetchList())    {        HttpModuleAction httpModuleAction = new HttpModuleAction(current.Name, current.Type);
     //初始化module原来就是在这里 httpModuleCollection.AddModule(httpModuleAction.Entry.ModuleName, httpModuleAction.Entry.Create()); }
return httpModuleCollection;//最终都给了this._moduleCollection}

可以想象:最后某个地方调用this._moduleCollection就能得到初始化操作.其实就是这里进行各个module初始化的操作的:

private void InitModulesCommon()        {            int count = this._moduleCollection.Count;            for (int i = 0; i < count; i++)            {                this._currentModuleCollectionKey = this._moduleCollection.GetKey(i);                this._moduleCollection[i].Init(this);//这里其实就是调用了各个httpmodule的初始化方法            }            this._currentModuleCollectionKey = null;            this.InitAppLevelCulture();        }

但是,这个

this._moduleCollection

集合的数据也是来至于

HttpApplication._dynamicModuleRegistry.LockAndFetchList()

public ICollection<DynamicModuleRegistryEntry> LockAndFetchList(),如果这里的数据中加入我们动态注册的module,

那么就达到了动态注册的目的

public ICollection<DynamicModuleRegistryEntry> LockAndFetchList()        {            ICollection<DynamicModuleRegistryEntry> entries;            lock (this._lockObj)            {                this._entriesReadonly = true;                entries = this._entries;//即:我们往这个里面_entries加入我们需要的module就达到效果            }            return entries;        }

恰巧在httpapplication中,有一个注册module的方法,估计很多人都没有用过

public static void RegisterModule(Type moduleType)        {            RuntimeConfig appConfig = RuntimeConfig.GetAppConfig();            HttpRuntimeSection httpRuntime = appConfig.HttpRuntime;            if (httpRuntime.AllowDynamicModuleRegistration)            {                HttpApplication.RegisterModuleInternal(moduleType);                return;            }            throw new InvalidOperationException(SR.GetString("DynamicModuleRegistrationOff"));        }
internal static void RegisterModuleInternal(Type moduleType)        {            HttpApplication._dynamicModuleRegistry.Add(moduleType);//从这里,我们可以看出该方法恰巧就可以动态注册.        }

 

public void Add(Type moduleType)        {            if (moduleType == null)            {                throw new ArgumentNullException("moduleType");            }            if (!typeof(IHttpModule).IsAssignableFrom(moduleType))            {                string message = string.Format(CultureInfo.CurrentCulture, SR.GetString("DynamicModuleRegistry_TypeIsNotIHttpModule"), new object[]                {                    moduleType                });                throw new ArgumentException(message, "moduleType");            }            lock (this._lockObj)            {                if (this._entriesReadonly)                {                    throw new InvalidOperationException(SR.GetString("DynamicModuleRegistry_ModulesAlreadyInitialized"));                }                this._entries.Add(new DynamicModuleRegistryEntry(DynamicModuleRegistry.MakeUniqueModuleName(moduleType), moduleType.AssemblyQualifiedName));            }        }

恰巧其机制就重合了,也就是动态注册的效果来源于这里.

this._entries.Add

但我们实际中会发现,我们如果纯粹地调用httpapplication的RegisterModule方法是达不到目的,例如我们在Global文件中加入以下代码

public Global()        {            //DynamicModuleRegistry             HttpApplication.RegisterModule(typeof(CustomModule));            InitializeComponent();                       }

系统抛出异常:

 

行 26: 		{行 27: 			//DynamicModuleRegistry行 28: 			 HttpApplication.RegisterModule(typeof(CustomModule));行 29: 			InitializeComponent();   行 30: 			


源文件: c:\Users\qscq\Documents\SharpDevelop Projects\ASPNET_ST_1\ASPNET_ST_1\Global.asax.cs    行: 28 

  这又是为什么呢?

  其实异常的来源在于

   在 System.Web.DynamicModuleRegistry.Add(Type moduleType)

public void Add(Type moduleType)        {            if (moduleType == null)            {                throw new ArgumentNullException("moduleType");            }            if (!typeof(IHttpModule).IsAssignableFrom(moduleType))            {                string message = string.Format(CultureInfo.CurrentCulture, SR.GetString("DynamicModuleRegistry_TypeIsNotIHttpModule"), new object[]                {                    moduleType                });                throw new ArgumentException(message, "moduleType");            }            lock (this._lockObj)            {                if (this._entriesReadonly)                {                    throw new InvalidOperationException(SR.GetString("DynamicModuleRegistry_ModulesAlreadyInitialized"));                }                this._entries.Add(new DynamicModuleRegistryEntry(DynamicModuleRegistry.MakeUniqueModuleName(moduleType), moduleType.AssemblyQualifiedName));            }        }

 

  也就是说,_entriesReadonly此刻已经是true了, 也就是在其true之前加入module就没有问题了.那什么时候变成true的呢?其实就是前面讲到的httpapplication自己初始化的时候,即InitModules方法中.也就是说,我们要抢在系统调用该方法前,调用

HttpApplication.RegisterModule方法就可以了.

三、总结

  如上面说的那样,系统自己调用了HttpApplication.RegisterModule,在调用此方法前,我们能够动态注册module即可.

汤姆大叔给出了

[assembly: PreApplicationStartMethod(typeof(WebApplication1.Test.PreApplicationStartCode), "PreStart")]

 

  该方法显然可以达到目标.但我们可以直接来得更简单写,直接Global加一个静态构造函数

  即:

static   Global(){            HttpApplication.RegisterModule(typeof(CustomModule));         }

   

四、感谢

  感谢几日来大家关注,我会继续写好,兄台,求推荐、关注.

大赠送的东西,大家可以好好看看,算是回馈大家的支持