<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      基于ASP.NET MVC3 Razor的模塊化/插件式架構實現

      本文主要探討了一種基于ASP.NET MVC3 Razor的模塊化(Plugin)/插件(plugin)式架構的實現方法。本文借鑒了《Compile your asp.net mvc Razor views into a seperate dll》作者提供的方法。

      項目管家 - 專注于項目管理軟件,項目管理工具項目管理系統,讓團隊協作更高效

      敬請注意。其實ASP.NET MVC的模塊化(Plugin)/插件(plugin)式架構討論的很多,但基于Razor視圖引擎的很少(如:MVC2插件架構例子都是基于WebForm的,MVCContrib Portable Areas也是,還有這個Plugin架構)。要么就是非常復雜非常重量級的框架,例如Orchard CMS的模塊化做的很好,可惜太重量級了,也沒獨立的模塊可以剝離出來。所以我們追尋的是簡單的基于ASP.NET MVC3 Razor的模塊化(Plugin)/插件(plugin)式架構的實現方法。本文最后實現的項目結構如下圖:(插件都放到~/Plugin目錄下,按功能劃分模塊,每個模塊都有M,V,C)

      3-5-2012 5-07-19 PM

      其中,業務模塊(class library project)包含其所有的視圖、控制器等,模型可以放在里面也可以單獨放一個project。主web項目沒有引用業務模塊,業務模塊會編譯到主web項目的~/plugin目錄下面(注意:不是bin目錄),然后當web應用啟動的時候自動加載plugin目錄下面的模塊。最后運行起來的效果如下圖:

      3-6-2012 10-28-51 AM

      其中紅色的區域都是plugin進去的,那個tab的標題plugin到母版頁的主菜單,tab內容也來自plugin。下面說說如何實現這樣的ASP.NET MVC插件式plugin架構(模塊化架構)。

      實現的難點在動態加載UI視圖(*.cshtml, _layout.cshtml, _viewStart.cshtml)

      廢話少說,直入要害?;贏SP.NET MVC3 Razor的編譯發生在兩個層面:

      • 控制器(Controller), 模型(Models),和其它所有的C#代碼等有msbuild(或者VisualStudio)編譯到bin目錄下的程序集(assembly)
      • 視圖(*.aspx, *.cshtml)由ASP.NET在運行時動態編譯。當一個Razor視圖(*.cshtml)顯示前,Razor視圖引擎調用BuildManager把視圖(*.cshtml)編譯到動態程序集assembly,然后使用Activator.CreateInstance來實例化新編譯出來的對象,最后顯示出來。如果視圖(*.cshtml)用到@model綁定model,那么還會自動加載bin或者GAC里面的Model。

      所以如果我們要動態加載插件(plugin),用反射bin目錄下的程序集(assembly)的方法很容易搞定上面的第一部分(C#代碼的部分),但UI視圖的部分(上面第二部分)(特別是*.cshtml, 母版_layout.cshtml, 基視圖_viewStart.cshtml)就比較難搞定。而且每次報錯都是一樣的,那就是Controller找不到相應的視圖View,基本不知所云而且根本不是要點:view …. or its master was not found or no view engine supports the searched locations. The following locations were searched: …,因此要搞定UI視圖的部分(上面第二部分)(特別是*.cshtml, 母版_layout.cshtml, 基視圖_viewStart.cshtml),就需要自己動手了,基本原理是:

      • 重載RazorBuildProvider,用來動態編譯視圖
      • 實現一個自定義VirtualPathProvider,從虛擬路徑自定義判斷讀取資源(從插件中加載資源),如果要使用編譯的視圖就返回編譯的VirtualFile
      • 實現一個容器Dictionary保存已編譯的視圖和虛擬路徑,例如path <~/views/team/index.cshtml> type <Area.Module2.Views.Team._Page_Views_Team_Index_cshtml>,或者path <~/views/_viewstart.cshtml> type <Area.Module1.Views._Page_Views__ViewStart_cshtml>

      代碼:自定義VirtualPathProvider,從虛擬路徑自定義判斷讀取資源(從插件中加載資源),如果要使用編譯的視圖就返回編譯的VirtualFile

         1: using System;
         2: using System.Collections.Generic;
         3: using System.Linq;
         4: using System.Reflection;
         5: using System.Web.Caching;
         6: using System.Web.Hosting;
         7: using System.Web.WebPages;
         8:  
         9: namespace Common.Framework
        10: {
        11:     public class CompiledVirtualPathProvider: VirtualPathProvider
        12:     {
        13:         /// <summary>
        14:         /// Gets a value that indicates whether a file exists in the virtual file system.
        15:         /// </summary>
        16:         /// <returns>
        17:         /// true if the file exists in the virtual file system; otherwise, false.
        18:         /// </returns>
        19:         /// <param name="virtualPath">The path to the virtual file.</param>
        20:         public override bool FileExists(string virtualPath)
        21:         {
        22:             return
        23:                 GetCompiledType(virtualPath) != null 
        24:                 || Previous.FileExists(virtualPath);
        25:         }
        26:  
        27:         public Type GetCompiledType(string virtualPath)
        28:         {
        29:             return ApplicationPartRegistry.Instance.GetCompiledType(virtualPath);
        30:         }
        31:  
        32:         /// <summary>
        33:         /// Gets a virtual file from the virtual file system.
        34:         /// </summary>
        35:         /// <returns>
        36:         /// A descendent of the <see cref="T:System.Web.Hosting.VirtualFile"/> class that represents a file in the virtual file system.
        37:         /// </returns>
        38:         /// <param name="virtualPath">The path to the virtual file.</param>
        39:         public override VirtualFile GetFile(string virtualPath)
        40:         {
        41:             if (Previous.FileExists(virtualPath))
        42:             {
        43:                 return Previous.GetFile(virtualPath);
        44:             }
        45:             var compiledType = GetCompiledType(virtualPath);
        46:             if (compiledType != null)
        47:             {
        48:                 return new CompiledVirtualFile(virtualPath, compiledType);
        49:             }
        50:             return null;
        51:         }
        52:  
        53:         public override System.Web.Caching.CacheDependency GetCacheDependency(string virtualPath, System.Collections.IEnumerable virtualPathDependencies, DateTime utcStart)
        54:         {
        55:             if (virtualPathDependencies == null)
        56:                 return Previous.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
        57:  
        58:             return Previous.GetCacheDependency(virtualPath, 
        59:                     from vp in virtualPathDependencies.Cast<string>()
        60:                     where GetCompiledType(vp) == null
        61:                     select vp
        62:                   , utcStart);
        63:         }
        64:  
        65:     }
        66: }

      代碼:容器Dictionary保存已編譯的視圖和虛擬路徑,例如path <~/views/team/index.cshtml> type <Area.Module2.Views.Team._Page_Views_Team_Index_cshtml>,路徑注冊以后,會從容器庫全局搜索所有注冊過的視圖,也就是說即使你視圖引用的_layout.cshtml和_viewStart.cshtml在其他的Class library project照樣可以找到。

         1: using System;
         2: using System.Collections.Generic;
         3: using System.Diagnostics;
         4: using System.Linq;
         5: using System.Reflection;
         6: using System.Web;
         7: using System.Web.WebPages;
         8:  
         9: namespace Common.Framework
        10: {
        11:     public class DictionaryBasedApplicationPartRegistry : IApplicationPartRegistry
        12:     {
        13:         private static readonly Type webPageType = typeof(WebPageRenderingBase); 
        14:         private readonly Dictionary<string, Type> registeredPaths = new Dictionary<string, Type>();
        15:  
        16:         /// <summary>
        17:         /// 
        18:         /// </summary>
        19:         /// <param name="virtualPath"></param>
        20:         /// <returns></returns>
        21:         public virtual Type GetCompiledType(string virtualPath)
        22:         {
        23:             if (virtualPath == null) throw new ArgumentNullException("virtualPath");
        24:  
        25:             //Debug.WriteLine(String.Format("---GetCompiledType : virtualPath <{0}>", virtualPath));
        26:  
        27:             if (virtualPath.StartsWith("/"))
        28:                 virtualPath = VirtualPathUtility.ToAppRelative(virtualPath);
        29:             if (!virtualPath.StartsWith("~"))
        30:                 virtualPath = !virtualPath.StartsWith("/") ? "~/" + virtualPath : "~" + virtualPath;
        31:             virtualPath = virtualPath.ToLower();
        32:             return registeredPaths.ContainsKey(virtualPath)
        33:                        ? registeredPaths[virtualPath]
        34:                        : null;
        35:         }
        36:  
        37:         public void Register(Assembly applicationPart)
        38:         {
        39:             ((IApplicationPartRegistry)this).Register(applicationPart, null);
        40:         }
        41:  
        42:         public virtual void Register(Assembly applicationPart, string rootVirtualPath)
        43:         {
        44:             //Debug.WriteLine(String.Format("---Register assembly <{0}>, path <{1}>", applicationPart.FullName, rootVirtualPath));
        45:  
        46:             foreach (var type in applicationPart.GetTypes().Where(type => type.IsSubclassOf(webPageType)))
        47:             {
        48:                 //Debug.WriteLine(String.Format("-----Register type <{0}>, path <{1}>", type.FullName, rootVirtualPath));
        49:  
        50:                 ((IApplicationPartRegistry)this).RegisterWebPage(type, rootVirtualPath);
        51:             }
        52:         }
        53:  
        54:         public void RegisterWebPage(Type type)
        55:         {
        56:             ((IApplicationPartRegistry)this).RegisterWebPage(type, string.Empty);
        57:         }
        58:  
        59:         public virtual void RegisterWebPage(Type type, string rootVirtualPath)
        60:         {
        61:             var attribute = type.GetCustomAttributes(typeof(PageVirtualPathAttribute), false).Cast<PageVirtualPathAttribute>().SingleOrDefault<PageVirtualPathAttribute>();
        62:             if (attribute != null)
        63:             {
        64:                 var rootRelativeVirtualPath = GetRootRelativeVirtualPath(rootVirtualPath ?? "", attribute.VirtualPath);
        65:  
        66:                 //Debug.WriteLine(String.Format("---Register path/type : path <{0}> type <{1}>", rootRelativeVirtualPath.ToLower(),
        67:                 //                              type.FullName));
        68:                 registeredPaths[rootRelativeVirtualPath.ToLower()] = type;
        69:             }
        70:         }
        71:  
        72:         static string GetRootRelativeVirtualPath(string rootVirtualPath, string pageVirtualPath)
        73:         {
        74:             string relativePath = pageVirtualPath;
        75:             if (relativePath.StartsWith("~/", StringComparison.Ordinal))
        76:             {
        77:                 relativePath = relativePath.Substring(2);
        78:             }
        79:             if (!rootVirtualPath.EndsWith("/", StringComparison.OrdinalIgnoreCase))
        80:             {
        81:                 rootVirtualPath = rootVirtualPath + "/";
        82:             }
        83:             relativePath = VirtualPathUtility.Combine(rootVirtualPath, relativePath);
        84:             if (!relativePath.StartsWith("~"))
        85:             {
        86:                 return !relativePath.StartsWith("/") ? "~/" + relativePath : "~" + relativePath;
        87:             }
        88:             return relativePath;
        89:         }
        90:     }
        91: }

      下面的代碼很關鍵,用PreApplicationStartMethod關鍵字(.NET 4.0開始支持)使得代碼在Application_Start之前執行。

      有關[assembly: PreApplicationStartMethod(typeof(SomeClassLib.Initializer), "Initialize")]詳細信息請參考這個頁面這個頁面

         1: using System.Web;
         2: using System.Web.Compilation;
         3: using System.Web.Hosting;
         4: using Common.Framework;
         5: using Common.PrecompiledViews;
         6:  
         7: [assembly: PreApplicationStartMethod(typeof(PreApplicationStartCode), "Start")]
         8:  
         9: namespace Common.Framework
        10: {
        11:     public static class PreApplicationStartCode
        12:     {
        13:         private static bool _startWasCalled;
        14:  
        15:         public static void Start()
        16:         {
        17:             if (_startWasCalled)
        18:             {
        19:                 return;
        20:             }
        21:             _startWasCalled = true;
        22:  
        23:             //Register virtual paths
        24:             HostingEnvironment.RegisterVirtualPathProvider(new CompiledVirtualPathProvider());
        25:  
        26:             //Load Plugin Folder, 
        27:             PluginLoader.Initialize();
        28:         }
        29:     }
        30: }

      代碼:PluginLoader,加載plugin目錄里面的東東(assembly和module配置文件)

         1: using System;
         2: using System.Collections.Generic;
         3: using System.IO;
         4: using System.Linq;
         5: using System.Reflection;
         6: using System.Text;
         7: using System.Threading;
         8: using System.Web;
         9: using System.Web.Compilation;
        10: using System.Web.Hosting;
        11: using Common.Framework;
        12: using Common.PrecompiledViews;
        13:  
        14: //[assembly: PreApplicationStartMethod(typeof(PluginLoader), "Initialize")]
        15:  
        16: namespace Common.PrecompiledViews
        17: {
        18:     public class PluginLoader
        19:     {
        20:         public static void Initialize(string folder = "~/Plugin")
        21:         {
        22:             LoadAssemblies(folder);
        23:             LoadConfig(folder);
        24:         }
        25:  
        26:         private static void LoadConfig(string folder, string defaultConfigName="*.config")
        27:         {
        28:             var directory = new DirectoryInfo(HostingEnvironment.MapPath(folder));
        29:             var configFiles = directory.GetFiles(defaultConfigName, SearchOption.AllDirectories).ToList();
        30:             if (configFiles.Count == 0) return;
        31:  
        32:             foreach (var configFile in configFiles.OrderBy(s => s.Name))
        33:             {
        34:                 ModuleConfigContainer.Register(new ModuleConfiguration(configFile.FullName));
        35:             }
        36:         }
        37:  
        38:         private static void LoadAssemblies(string folder)
        39:         {
        40:             var directory = new DirectoryInfo(HostingEnvironment.MapPath(folder));
        41:             var binFiles = directory.GetFiles("*.dll", SearchOption.AllDirectories).ToList();
        42:             if (binFiles.Count == 0) return;
        43:  
        44:             foreach (var plug in binFiles)
        45:             {
        46:                 //running in full trust
        47:                 //************
        48:                 //if (GetCurrentTrustLevel() != AspNetHostingPermissionLevel.Unrestricted)
        49:                 //set in web.config, probing to plugin\temp and copy all to that folder
        50:                 //************************
        51:                 var shadowCopyPlugFolder = new DirectoryInfo(AppDomain.CurrentDomain.DynamicDirectory);
        52:                 var shadowCopiedPlug = new FileInfo(Path.Combine(shadowCopyPlugFolder.FullName, plug.Name));
        53:                 File.Copy(plug.FullName, shadowCopiedPlug.FullName, true); //TODO: Exception handling here...
        54:                 var shadowCopiedAssembly = Assembly.Load(AssemblyName.GetAssemblyName(shadowCopiedPlug.FullName));
        55:  
        56:                 //add the reference to the build manager
        57:                 BuildManager.AddReferencedAssembly(shadowCopiedAssembly);
        58:             }
        59:         }
        60:  
        61:         //private static AspNetHostingPermissionLevel GetCurrentTrustLevel()
        62:         //{
        63:         //    foreach (AspNetHostingPermissionLevel trustLevel in
        64:         //        new AspNetHostingPermissionLevel[]
        65:         //            {
        66:         //                AspNetHostingPermissionLevel.Unrestricted,
        67:         //                AspNetHostingPermissionLevel.High,
        68:         //                AspNetHostingPermissionLevel.Medium,
        69:         //                AspNetHostingPermissionLevel.Low,
        70:         //                AspNetHostingPermissionLevel.Minimal
        71:         //            })
        72:         //    {
        73:         //        try
        74:         //        {
        75:         //            new AspNetHostingPermission(trustLevel).Demand();
        76:         //        }
        77:         //        catch (System.Security.SecurityException)
        78:         //        {
        79:         //            continue;
        80:         //        }
        81:  
        82:         //        return trustLevel;
        83:         //    }
        84:  
        85:         //    return AspNetHostingPermissionLevel.None;
        86:         //}
        87:  
        88:     }
        89: }

      此外,使用SingleFileGenerator的優點是性能提升,缺點是修改了視圖就要重新編譯。

      如何讓ASP.NET加載BIN目錄之外的路徑的Assembly

      我們把各個模塊編譯出來的assembly和各個模塊的配置文件自動放到一個bin平級的plugin目錄,然后web應用啟動的時候自動掃描這個plugin目錄并加載各個模塊plugin,這個怎么做到的?大家也許知道,ASP.NET只允許讀取Bin目錄下的assbmely,不可以讀取其他路徑,包括Bin\abc等,即使在web.config這樣配置probing也不行:(不信你可以試一下)

         1: <configuration> Element
         2:   <runtime> Element
         3:     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
         4:       <probing privatePath="bin;bin\abc;plugin;"/>
         5:     </assemblyBinding>
         6:    </runtime>
         7: </configuration>

      這個和TrustLevel有關,在Full Trust的情況下,可以這樣讀取非Bin目錄下的assembly:

      首先在和Bib平級的地方建一個目錄Plugin,然后在模塊class library project的屬性里面加一個postBuildEvent,就是說在編譯完成以后把模塊的assbmely自動拷貝到主web項目的plugin目錄:

         1: copy /Y "$(TargetDir)$(ProjectName).dll" "$(SolutionDir)ModularWebApplication\Plugin\"
         2: copy /Y "$(TargetDir)$(ProjectName).config" "$(SolutionDir)ModularWebApplication\Plugin\"
         3:  

      然后用下面的代碼加載Plugin目錄下的assembly:(只看LoadAssembly那一段)

         1: using System;
         2: using System.Collections.Generic;
         3: using System.IO;
         4: using System.Linq;
         5: using System.Reflection;
         6: using System.Text;
         7: using System.Threading;
         8: using System.Web;
         9: using System.Web.Compilation;
        10: using System.Web.Hosting;
        11: using Common.Framework;
        12: using Common.PrecompiledViews;
        13:  
        14: //[assembly: PreApplicationStartMethod(typeof(PluginLoader), "Initialize")]
        15:  
        16: namespace Common.PrecompiledViews
        17: {
        18:     public class PluginLoader
        19:     {
        20:         public static void Initialize(string folder = "~/Plugin")
        21:         {
        22:             LoadAssemblies(folder);
        23:             LoadConfig(folder);
        24:         }
        25:  
        26:         private static void LoadConfig(string folder, string defaultConfigName="*.config")
        27:         {
        28:             var directory = new DirectoryInfo(HostingEnvironment.MapPath(folder));
        29:             var configFiles = directory.GetFiles(defaultConfigName, SearchOption.AllDirectories).ToList();
        30:             if (configFiles.Count == 0) return;
        31:  
        32:             foreach (var configFile in configFiles.OrderBy(s => s.Name))
        33:             {
        34:                 ModuleConfigContainer.Register(new ModuleConfiguration(configFile.FullName));
        35:             }
        36:         }
        37:  
        38:         private static void LoadAssemblies(string folder)
        39:         {
        40:             var directory = new DirectoryInfo(HostingEnvironment.MapPath(folder));
        41:             var binFiles = directory.GetFiles("*.dll", SearchOption.AllDirectories).ToList();
        42:             if (binFiles.Count == 0) return;
        43:  
        44:             foreach (var plug in binFiles)
        45:             {
        46:                 //running in full trust
        47:                 //************
        48:                 //if (GetCurrentTrustLevel() != AspNetHostingPermissionLevel.Unrestricted)
        49:                 //set in web.config, probing to plugin\temp and copy all to that folder
        50:                 //************************
        51:                 var shadowCopyPlugFolder = new DirectoryInfo(AppDomain.CurrentDomain.DynamicDirectory);
        52:                 var shadowCopiedPlug = new FileInfo(Path.Combine(shadowCopyPlugFolder.FullName, plug.Name));
        53:                 File.Copy(plug.FullName, shadowCopiedPlug.FullName, true); //TODO: Exception handling here...
        54:                 var shadowCopiedAssembly = Assembly.Load(AssemblyName.GetAssemblyName(shadowCopiedPlug.FullName));
        55:  
        56:                 //add the reference to the build manager
        57:                 BuildManager.AddReferencedAssembly(shadowCopiedAssembly);
        58:             }
        59:         }
        60:  
        61:         //private static AspNetHostingPermissionLevel GetCurrentTrustLevel()
        62:         //{
        63:         //    foreach (AspNetHostingPermissionLevel trustLevel in
        64:         //        new AspNetHostingPermissionLevel[]
        65:         //            {
        66:         //                AspNetHostingPermissionLevel.Unrestricted,
        67:         //                AspNetHostingPermissionLevel.High,
        68:         //                AspNetHostingPermissionLevel.Medium,
        69:         //                AspNetHostingPermissionLevel.Low,
        70:         //                AspNetHostingPermissionLevel.Minimal
        71:         //            })
        72:         //    {
        73:         //        try
        74:         //        {
        75:         //            new AspNetHostingPermission(trustLevel).Demand();
        76:         //        }
        77:         //        catch (System.Security.SecurityException)
        78:         //        {
        79:         //            continue;
        80:         //        }
        81:  
        82:         //        return trustLevel;
        83:         //    }
        84:  
        85:         //    return AspNetHostingPermissionLevel.None;
        86:         //}
        87:  
        88:     }
        89: }

      如果不是Full Trust,例如Medium Trust的情況下參考這個帖子《Developing-a-plugin-framework-in-ASPNET-with-medium-trust》。

      如何在_layout.cshtml的主菜單注入plugin的菜單

      在母版頁_layout.cshtml有個主菜單,一般是這樣寫的:

         1: <ul>
         2:    <li>@Html.ActionLink("Home", "Index", "Home")</li>
         3:    <li>@Html.ActionLink("About", "About", "Home")</li>
         4:    <li>@Html.ActionLink("Team", "Index", "Team")</li>
         5: </ul>

      現在我們如何實現從模塊插入plugin到這個主菜單呢?這個有點難。因為大家知道,_layout.cshml母版沒有controller。怎么實現呢?方法是用controller基類,讓所有controller繼承自這個基類。然后在基類里面,讀取plugin目錄里面的配置文件,獲取所有模塊需要插入的主菜單項,然后放入viewBag,這樣在_Layout.cshtml就可以獲取viewBag,類似這樣:

         1: <ul>
         2:    @foreach (MainMenuItemModel entry in ViewBag.MainMenuItems)
         3:     {
         4:         <li>@Html.ActionLink(entry.Text, 
         5:                entry.ActionName, 
         6:                 entry.ControllerName)</li>
         7:     }
         8: </ul>

      代碼:基類Controller,讀取plugin目錄里面的配置文件,獲取所有模塊需要插入的主菜單項,然后放入viewBag

         1: using System;
         2: using System.Collections;
         3: using System.Collections.Generic;
         4: using System.ComponentModel;
         5: using System.Linq;
         6: using System.Net.Mime;
         7: using System.Text;
         8: using System.Web.Mvc;
         9:  
        10: namespace Common.Framework
        11: {
        12:     public class BaseController : Controller
        13:     {
        14:         protected override void Initialize(System.Web.Routing.RequestContext requestContext)
        15:         {
        16:             base.Initialize(requestContext);
        17:  
        18:             // retireve data from plugins
        19:             IEnumerable<ModuleConfiguration> ret = ModuleConfigContainer.GetConfig();
        20:  
        21:             var data = (from c in ret
        22:                         from menu in c.MainMenuItems
        23:                         select new MainMenuItemModel
        24:                                    {
        25:                                        Id = menu.Id, ActionName = menu.ActionName, ControllerName = menu.ControllerName, Text = menu.Text
        26:                                    }).ToList();
        27:             
        28:             ViewBag.MainMenuItems = data.AsEnumerable();
        29:         }
        30:  
        31:     }
        32: }

      代碼:ModuleConfigContainer,用到單例模式,只讀取一次

         1: using System;
         2: using System.Collections.Generic;
         3: using System.Linq;
         4: using System.Text;
         5:  
         6: namespace Common.Framework
         7: {
         8:     public static class ModuleConfigContainer
         9:     {
        10:         static ModuleConfigContainer()
        11:         {
        12:             Instance = new ModuleConfigDictionary();
        13:         }
        14:  
        15:         internal static IModuleConfigDictionary Instance { get; set; }
        16:  
        17:         public static void Register(ModuleConfiguration item)
        18:         {
        19:             Instance.Register(item);
        20:         }
        21:  
        22:         public static IEnumerable<ModuleConfiguration> GetConfig()
        23:         {
        24:             return Instance.GetConfigs();
        25:         }
        26:     }
        27: }

      代碼:ModuleConfigDictionary

         1: using System;
         2: using System.Collections.Generic;
         3: using System.Linq;
         4: using System.Text;
         5:  
         6: namespace Common.Framework
         7: {
         8:     public class ModuleConfigDictionary : IModuleConfigDictionary
         9:     {
        10:         private readonly Dictionary<string, ModuleConfiguration>  _configurations = new Dictionary<string, ModuleConfiguration>();
        11:  
        12:         public IEnumerable<ModuleConfiguration> GetConfigs()
        13:         {
        14:             return _configurations.Values.AsEnumerable();
        15:         }
        16:  
        17:         public void Register(ModuleConfiguration item)
        18:         {
        19:             if(_configurations.ContainsKey(item.ModuleName))
        20:             {
        21:                 _configurations[item.ModuleName] = item;
        22:             }
        23:             else
        24:             {
        25:                 _configurations.Add(item.ModuleName, item);
        26:             }
        27:         }
        28:     }
        29: }

      代碼:ModuleConfiguration,讀取模塊的配置文件

         1: using System;
         2: using System.Collections.Generic;
         3: using System.IO;
         4: using System.Linq;
         5: using System.Text;
         6: using System.Xml;
         7: using System.Xml.Linq;
         8:  
         9: namespace Common.Framework
        10: {
        11:     public class ModuleConfiguration
        12:     {
        13:         public ModuleConfiguration(string filePath)
        14:         {
        15:             try
        16:             {
        17:                 var doc = XDocument.Load(filePath);
        18:                 var root = XElement.Parse(doc.ToString());
        19:  
        20:                 if (!root.HasElements) return;
        21:  
        22:                 var module = from e in root.Descendants("module")
        23:                              //where e.Attribute("name").Value == "xxxx"
        24:                              select e;
        25:  
        26:                 if (!module.Any()) return;
        27:  
        28:                 ModuleName = module.FirstOrDefault().Attribute("name").Value;
        29:  
        30:                 var menus = from e in module.FirstOrDefault().Descendants("menu")
        31:                             select e;
        32:  
        33:                 if (!menus.Any()) return;
        34:  
        35:                 var menuitems = menus.Select(xElement => new MainMenuItemModel
        36:                                                              {
        37:                                                                  Id = xElement.Attribute("id").Value,
        38:                                                                  Text = xElement.Attribute("text").Value,
        39:                                                                  ActionName = xElement.Attribute("action").Value,
        40:                                                                  ControllerName = xElement.Attribute("controller").Value
        41:                                                              }).ToList();
        42:  
        43:                 MainMenuItems = menuitems;
        44:             }
        45:             catch
        46:             {
        47:                 //TODO: logging
        48:             }
        49:         }
        50:         public string ModuleName { get; set; }
        51:         public IEnumerable<MainMenuItemModel> MainMenuItems { get; set; }
        52:     }
        53: }

      每個模塊的配置文件為{projectName}.config,格式如下:

         1: <?xml version="1.0" encoding="utf-8" ?>
         2: <configuration>
         3:   <module name="Module2">
         4:     <mainmenu>
         5:       <menu id="modul2" text="Team" action="Index" controller="Team"/>
         6:     </mainmenu>
         7:   </module>
         8: </configuration>

      為了簡單起見,只保留了注入主菜單的部分,為了讓讀者簡單易懂。明白了以后你自己可以任意擴展…

      代碼:IModuleConfigDictionary,接口

      dddd

      模塊配置文件{projectName}.config的位置:

      Untitled

      為什么每個模塊的Class library project都需要一個web.config呢?因為如果沒有這個,那就沒有Razor智能提示,大家可以參考這篇文章《How to get Razor intellisense for @model in a class library project》。

       

      閑話幾句插件式架構(Plugin Architecture)或者模塊化(Modular)架構

      插件式架構(Plugin Architecture)或者模塊化(Modular)架構是大型應用必須的架構,關于什么是Plugin,什么是模塊化模式,這種架構的優缺點等我就不說了,自己百谷歌度。關于.NET下面的插件式架構和模塊化開發實現方法,基本上用AppDomain實現,當檢測到一個新的插件Plugin時,實例化一個新的AppDomain并加載Assembly反射類等,由于AppDomain很好的隔離各個Plugin,所以跨域通信要用MarshalByRefObject類,具體做法可以參考這篇文章《基于AppDomain的"插件式"開發》。另外,有很多框架提供了模塊化/插件開發的框架,例如PrismMEF(Managed Extensibility Framework,.NET 4.0 內置)等。

      客戶端插件架構

      還有一種插件架構是客戶端插件架構(Javascript 模塊化),如jQuery UI Widget FactorySilk Project就是很好的例子。

      本文源碼下載

      源碼下載請點擊此處。運行源碼之前務必閱讀此文和本文。注意:本文拋磚引玉,力求簡單,易懂,并非完整的架構實現,更多豐富的功能實現一切皆有可能,只要在理解的基礎上。

      posted on 2012-06-03 18:50  項目管理之家  閱讀(9449)  評論(17)    收藏  舉報

      導航

      主站蜘蛛池模板: 亚洲欧洲日韩国内高清| 亚洲精品天堂在线观看| 波多野结衣的av一区二区三区| 99国精品午夜福利视频不卡99| 久久道精品一区二区三区| 男女裸体影院高潮| 尹人香蕉久久99天天拍| 亚洲欧美一区二区三区图片| 99国精品午夜福利视频不卡99| 精品粉嫩国产一区二区三区| 她也色tayese在线视频| 国产精品毛片在线看不卡| 亚洲色大成网站WWW久久| 亚洲国产精品久久久久婷婷老年| 欧美片内射欧美美美妇| 中文字幕精品亚洲无线码二区| 午夜精品久久久久久| 美日韩精品一区二区三区| 国产中文三级全黄| 成人免费无码大片A毛片抽搐色欲 成人啪精品视频网站午夜 | 国产亚洲精品第一综合另类| 亚洲AV高清一区二区三区尤物| 99精品久久毛片a片| 亚洲国产日韩精品久久| 宅男噜噜噜66在线观看| 久久精品国产99麻豆蜜月| 人人入人人爱| 欧美视频二区欧美影视| 岛国岛国免费v片在线观看| 精品一区二区三区东京热| 国产成人精品久久性色av| 国产成人av电影在线观看第一页| 熟妇人妻一区二区三区四区| 国产真实交换配乱婬95视频| 秋霞人妻无码中文字幕| 公喝错春药让我高潮| 成人无遮挡裸免费视频在线观看| 亚洲成在人天堂一区二区| 精品乱码一区二区三四五区| 亚洲精品熟女一区二区| 久久99精品久久久久久齐齐|