一、关于动态注册的问题

  很多人看过汤姆大叔的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.5下是如此的,这是不含MVC框架的情况下)

二、关于httpmodule的初始化

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

// System.Web.HttpApplication
internal 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 = ; 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)); }

  

四、感谢

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

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

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

  1. 在Asp.net 4.0 中动态注册HttpModule

    using System; using System.Web; using Microsoft.Web.Infrastructure; namespace MvcApplication1 { publ ...

  2. MVC之前的那点事儿系列(6):动态注册HttpModule

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

  3. 不使用配置文件动态注册HttpModule

    在asp.net 4.0中,提供了一种不通过修改配置文件注册Module的方法.从.net3.5开始,新提供的PreApplicationStartMethodAttribute特性可以应用在程序集上 ...

  4. 动态注册HttpModule

    动态注册HttpModule 2014-06-05 08:58 by 汤姆大叔, 757 阅读, 4 评论, 收藏, 编辑 文章内容 通过前面的章节,我们知道HttpApplication在初始化的时 ...

  5. Mvc动态注册HttpModule详解

    序言 注册Httpmodule可以让我们使用HttpApplication对象中的处理管道事件.目前大家所熟知的应该有2种方式来使用HttpApplication对象中的处理管道事件.第一种是通过Gl ...

  6. MVC源码解析 - 配置注册 / 动态注册 HttpModule

    本来这一篇, 是要继续 Pipeline 的, 但是在 Pipeline之前, 我看到了InitModules()方法, 所以决定, 在中间穿插一篇进来. 这一篇来讲一下 IHttpModule 的加 ...

  7. 动态注册HttpModule管道,实现global.asax功能

    1.所用类库有 Microsoft.Web.Infrastructure.dll 和WebActivator.dll 2.类代码如下 using System; using System.Collec ...

  8. 你必须知道ASP.NET知识------从IIS到httpmodule(第一篇)

    一.写在前面 最近有时间,顺便将这系列洗完,接着上文:IIS各个版本知识总结 这篇文章原本计划写到HttpHandler为止,但限于篇幅就写到httpmodule 本文有不足之处,求指正,希望我能将它 ...

  9. asp相关知识整理

    WWW----World Wide Web(万维网) URL----Uniform Resource Locator(统一资源定位符) HTTP----Hyper Text Transfer Prot ...

随机推荐

  1. VS2015安装&简单的C#单元测试

    <软件工程>开课已经三周了,三周的上课感觉就是老师教授的概念性东西少了不少,基本就是贯穿“做中学”的教学理念,三周的时间让我学到了挺多东西,很多东西都是课本没有的. 这周的任务就是安装VS ...

  2. Android零散

    2016-03-13 Android零散 ListView中嵌套GridView 要实现分组列表这样的效果:点击ListView中的分组名称,即展开此分组显示其包含的项目.使用ExpandableLi ...

  3. Code First开发系列之管理并发和事务

    返回<8天掌握EF的Code First开发>总目录 本篇目录 理解并发 理解积极并发 理解消极并发 使用EF实现积极并发 EF的默认并发 设计处理字段级别的并发应用 实现RowVersi ...

  4. Backbone源码分析(二)

    在传统MVC框架模式中,Model承担业务逻辑的任务.Backbone作为一个mvc框架,主要的业务逻辑交由Model与Collection来实现.Model代表领域对象,今天主要学一下Model源码 ...

  5. 使用Guava EventBus构建publish/subscribe系统

    Google的Guava类库提供了EventBus,用于提供一套组件内publish/subscribe的解决方案.事件总线EventBus,用于管理事件的注册和分发.在系统中,Subscribers ...

  6. 【完全开源】百度地图Web service API C#.NET版,带地图显示控件、导航控件、POI查找控件

    目录 概述 功能 如何使用 参考帮助 概述 源代码主要包含三个项目,BMap.NET.BMap.NET.WindowsForm以及BMap.NET.WinformDemo. BMap.NET 对百度地 ...

  7. Mac OS X上IntelliJ IDEA 13与Tomcat 8的Java Web开发环境搭建

    这标题实在有点拗口,不知道怎么写好,但看了标题也就明白文本的内容.最近几天在折腾这些玩意儿,所以写写总结.除了环境搭建,本文还是一篇入门级的上手教程. 去下载一些东西 JDK安装 Tomcat安装 T ...

  8. 黑科技:gif二维码

    本篇文章是缘于在微博上看到了一的有意思的东西.由于腾讯与阿里的竞争关系,如果你是一个大V,在微博上发布微信的二维码会被屏蔽掉.于是有人发现了这样一个现象:人眼有视觉暂留效应,手机的摄像头由于捕捉影像的 ...

  9. 【Java并发编程实战】-----synchronized

    在我们的实际应用当中可能经常会遇到这样一个场景:多个线程读或者.写相同的数据,访问相同的文件等等.对于这种情况如果我们不加以控制,是非常容易导致错误的.在java中,为了解决这个问题,引入临界区概念. ...

  10. Objective-C中的Strong、Copy与MutableCopy

    面试过程中经常被问到ARC中Strong.Copy的区别是什么.普通的回答是:一样.文艺(正确)的回答是:分情况(我擦!WQY#$&Y**%OWEUR) 可以先参考这篇文章http://www ...