MVC系列(6) 动态注册HttpModule

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

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

注:该DLL位置在C:\Program Files\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\Assemblies\下

我们发现了一个静态类DynamicModuleUtility,里面有个RegisterModule方法引起了我的注意:

// Call from PreAppStart to dynamically register an IHttpModule, just as if you had added it to the
// <modules> section in Web.config.
[SecuritySafeCritical]
public static void RegisterModule(Type moduleType) {
    if (DynamicModuleReflectionUtil.Fx45RegisterModuleDelegate != null) {
        // The Fx45 helper exists, so just call it directly.
        DynamicModuleReflectionUtil.Fx45RegisterModuleDelegate(moduleType);
    }
    else {
        // Use private reflection to perform the hookup.
        LegacyModuleRegistrar.RegisterModule(moduleType);
    }
}

通过代码和注释我们可以看到,这个方法就是让我们动态注册IHttpModule的,而且由于.Net4.5已经有helper类支持了,所以直接就可以用,其它版本使用LegacyModuleRegistrar.RegisterModule来动态注册IHttpModule 的。而这个方法里又分IIS6和IIS7集成或经典模式之分,代码大体上是一致的,我们这里就只分析IIS6版本的代码:

private static void AddModuleToClassicPipeline(Type moduleType) {
    // This works by essentially adding a new entry to the <httpModules> section defined
    // in ~/Web.config. Need to set the collection to read+write while we do this.   

    // httpModulesSection = RuntimeConfig.GetAppConfig().HttpModules;
    // httpModulesSection.Modules.bReadOnly = false;
    // httpModulesSection.Modules.Add(new HttpModuleAction(...));
    // httpModulesSection.Modules.bReadOnly = true;  

    HttpModulesSection httpModulesSection = null;
    try {
        object appConfig = _reflectionUtil.GetAppConfig();
        httpModulesSection = _reflectionUtil.GetHttpModulesFromAppConfig(appConfig);
        _reflectionUtil.SetConfigurationElementCollectionReadOnlyBit(httpModulesSection.Modules, false /* value */);   

        DynamicModuleRegistryEntry newEntry = CreateDynamicModuleRegistryEntry(moduleType);
        httpModulesSection.Modules.Add(new HttpModuleAction(newEntry.Name, newEntry.Type));
    }
    finally {
        if (httpModulesSection != null) {
            _reflectionUtil.SetConfigurationElementCollectionReadOnlyBit(httpModulesSection.Modules, true /* value */);
        }
    }
}

上面代码的注释非常重要,通过注释我们可以看到,该方法先从RuntimeConfig.GetAppConfig().HttpModules获取 HttpModules集合,然后在集合里添加需要注册的新HttpModule,那就是说HttpApplication在初始化所有 HttpModule之前必须将需要注册的HttpModule添加到这个集合里,那是在哪个周期呢?HttpApplication之前是 HostingEnvironment,那是不是在这里可以注册呢?我们去该类查看一下相关的代码,在Initialize方法里突然发现一个貌似很熟悉的代码BuildManager.CallPreStartInitMethods(),代码如下:

// call AppInitialize, unless the flag says not to do it (e.g. CBM scenario).
// Also, don't call it if HostingInit failed (VSWhidbey 210495)
if(!HttpRuntime.HostingInitFailed) {
    try {
        BuildManager.CallPreStartInitMethods();
        if ((hostingFlags & HostingEnvironmentFlags.DontCallAppInitialize) == 0) {
            BuildManager.CallAppInitializeMethod();
        }
    }
    catch (Exception e) {
        // could throw compilation errors in 'code' - report them with first http request
        HttpRuntime.InitializationException = e;   

        if ((hostingFlags & HostingEnvironmentFlags.ThrowHostingInitErrors) != 0) {
            throw;
        }
    }
}

通过去BuildManager类去查看该方法的详情,最终发现了如下这个方法:

internal static ICollection<MethodInfo> GetPreStartInitMethodsFromAssemblyCollection(IEnumerable<Assembly> assemblies) {
    List<MethodInfo> methods = new List<MethodInfo>();
    foreach (Assembly assembly in assemblies) {
        PreApplicationStartMethodAttribute[] attributes = null;
        try {
            attributes = (PreApplicationStartMethodAttribute[])assembly.GetCustomAttributes(typeof(PreApplicationStartMethodAttribute), inherit: true);
        }
        catch {
            // GetCustomAttributes invokes the constructors of the attributes, so it is possible that they might throw unexpected exceptions.
            // (Dev10 bug 831981)
        }   

        if (attributes != null && attributes.Length != 0) {
            Debug.Assert(attributes.Length == 1);
            PreApplicationStartMethodAttribute attribute = attributes[0];
            Debug.Assert(attribute != null);  

            MethodInfo method = null;
            // Ensure the Type on the attribute is in the same assembly as the attribute itself
            if (attribute.Type != null && !String.IsNullOrEmpty(attribute.MethodName) && attribute.Type.Assembly == assembly) {
                method = FindPreStartInitMethod(attribute.Type, attribute.MethodName);
            }  

            if (method != null) {
                methods.Add(method);
            }
            else {
                throw new HttpException(SR.GetString(SR.Invalid_PreApplicationStartMethodAttribute_value,
                    assembly.FullName,
                    (attribute.Type != null ? attribute.Type.FullName : String.Empty),
                    attribute.MethodName));
            }
        }
    }
    return methods;
}

本栏目更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.cn/webkf/aspx/

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索代码
, null
, 注册
, attribute
, httpmodule
, HttpModules
Attributes
mvc httpmodule、springmvc 动态定时器、spring mvc 动态url、springmvc 动态数据源、springmvc动态国际化,以便于您获取更多的相关知识。

时间: 2024-08-24 07:17:33

MVC系列(6) 动态注册HttpModule的相关文章

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

在asp.net 4.0中,提供了一种不通过修改配置文件注册Module的方法.从.net3.5开始,新提供的PreApplicationStartMethodAttribute特性可以应用在程序集上,使得自定义的网站初始化代码可以在web应用程序的Application_Start初始化环节之前就执行.这个步骤甚至在动态编译和执行Application_Start之前.对于每个程序集,可以定义一次,PreApplicationStartMethodAttribute定义如下: #region

MVC系列(7) WebActivator的实现原理详解

上篇文章,我们分析如何动态注册HttpModule的实现,本篇我们来分析一下通过上篇代码原理实现的WebActivator类库,WebActivator提供了3种功能,允许我们分别在HttpApplication初始化之前,之后以及ShutDown的时候分别执行指定的代码,示例如下: [assembly: WebActivator.PreApplicationStartMethod(typeof(A.InitClass1), "PreStart")] [assembly: WebAct

MVC系列(9) MVC如何在Pipeline中接管请求的

上个章节我们讲到了,可以在HttpModules初始化之前动态添加Route的方式来自定义自己的HttpHandler,最终接管请求的,那MVC是这么实现的么?本章节我们就来分析一下相关的MVC源码来验证一下我们的这个问题. 先创建一个MVC3的Web Application,选择默认的模板以便创建以后就默认包含HomeController和AccountController.我们知道MVC要先接管请求才能通过这些Controller来处理,那我们先去Global.asax.cs文件里看代码(定

MVC系列(8) UrlRouting的理解

根据对Http Runtime和Http Pipeline的分析,我们知道一个ASP.NET应用程序可以有多个HttpModuel,但是只能有一个HttpHandler,并且通过这个 HttpHandler的BeginProcessRequest(或ProcessRequest)来处理并返回请求,前面的章节将到了再 MapHttpHandler这个周期将会根据请求的URL来查询对应的HttpHandler,那么它是如何查找的呢? 一起我们在做自定义HttpHandler的时候,需要执行URL以及

(C#)Windows Shell 外壳编程系列7 - ContextMenu 注册文件右键菜单

原文 (C#)Windows Shell 外壳编程系列7 - ContextMenu 注册文件右键菜单   (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-)   接上一节:(C#)Windows Shell 外壳编程系列6 - 执行   从本节起,我所要讲述的是对 Windows 系统的"Shell 扩展"."Shell 扩展"从字面上分两个部分:Shell 与 Extension.Shell 指 Windows Explorer,而Extensi

爱上MVC系列~目录

MVC3配合Razor视图引擎使得我们在开发项目中更加快捷,以下是我在项目开发过程中整理的一些笔记,和大家一起分享一下 爱上MVC系列~目录 爱上MVC~Razor引擎时,在遍历中巧用Output.Write方法 爱上MVC~开发Areas模块时需要注意一下路由问题 爱上MVC~实体级标准验证 爱上MVC系列~PartialView()与View()真的一样吗? 爱上MVC系列~手动向路由表扔数据,不影响当前URL路由配对 爱上MVC系列~使用Func<string, HelperResult>

Oracle数据库动态注册和参数local_listener的使用方法

从Oracle8i版本开始,在oracle数据库当中,应用如果没有特殊需求的话,数据库监听不需要做出配置,oracle把这种方法称为动态注册.所谓动态注册,oracle通过PMON进程根据参数instance_name和service_names中的内容,把oracle数据库的信息注册到默认的1521端口的监听器上.不管服务器端有几个监听程序,oracle默认都是注册到1521端口的监听器,也就是说,对于其他端口的监听器来说,如果想要正常的识别远程客户端提供的信息,需要做出配置,也就是静态注册.

Oracle Listener的动态注册

在有Oracle Listener的动态注册之前,采用的是静态注册,所谓静态注册是指Oracle实例在启动时 ,读取listener.ora里的配置,然后注册到Listener,它主要有两个缺点: 1. Listener不知道Oracle实例的实时状态 2. listener.ora里的配置比较麻烦,常需要手动修改. 动态注册 所谓动态注册是指Oracle实例启动后,会通过pmon进程实时的把实例状态和参数 (instance_name,service_name)同步给Listener,其中参数

第十六章_动态注册和Servlet容器初始化

16.1.动态注册 为了使动态注册成为可能,ServletContext接口中还添加了以下方法,用来动态地创建Web对象: <T extends Filter>createFilter(Java.lang.Class<T> clazz) <T extends java.util.EventListener> createListener(java.lang.Class<T> clazz) <T extends Servlet> createSer