zoukankan      html  css  js  c++  java
  • 你必须知道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.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 = 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:UsersqscqDocumentsSharpDevelop ProjectsASPNET_ST_1ASPNET_ST_1Global.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));
             
    }

       

    四、感谢

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

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

  • 相关阅读:
    TL9000 电信业质量体系管理标准
    ISO/IEC 27001 信息安全管理体系认证
    编程要自学或报班这事你都想不明白, 那必然是你智商不够!
    Linux 计划任务 Crontab 笔记与总结(4)crontab 的日志
    中国象棋程序的设计与实现(一)--项目截图
    中国象棋程序的设计与实现(一)--项目截图
    C# XML 反序列化解析
    PHP开发实战权威指南-读书总结
    PHP开发实战权威指南-读书总结
    假如生活欺骗了你
  • 原文地址:https://www.cnblogs.com/humble/p/3924872.html
Copyright © 2011-2022 走看看