程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> ASP.NET >> 關於ASP.NET >> MVC系列(6) 動態注冊HttpModule

MVC系列(6) 動態注冊HttpModule

編輯:關於ASP.NET

通過前面的章節,我們知道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;   
}

本欄目

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved