如今正在作的項目是以長沙某個客戶的需求爲原型進行開發的,隨着業務的拓展,其餘城市相同行業的客戶也有相似的需求,在進行投標時,每一個客戶都有本身的頁面和功能要求,若是單純用長沙客戶的軟件版本,沒法徹底知足標書要求,所以須要對項目進行改造,考慮採用MVC插件化方式。css
現有項目使用的技術點主要是MVC+EF+jQuery,改造思路考慮將每個功能模塊抽取爲一個插件,在主Web項目中引用各插件,並將插件的css、js、views等文件拷貝到主Web項目的Plugins文件夾下。當有新客戶提出個性化需求時,將涉及到的模塊插件複製一份,而後進行個性化改造,新插件和原插件在mvc 路由上如出一轍,插件的名稱也同樣,這樣對於主Web項目來講兩個插件就如同一個同樣。項目其餘層(Biz、Model等其餘類庫)保持不變。html
具體改造方法:web
插件是一個MVC項目,要求必須包含:Controllers(控制器)、Models(ViewModel)、Content(樣式表)、Scripts、Views文件夾。mvc
項目屬性中的生成事件中,添加後期生成事件命令行:app
rd /s /q $(SolutionDir)MyApplication.Web\Plugins\Device xcopy /s /y $(ProjectDir)Views $(SolutionDir)MyApplication.Web\Plugins\Device\Views\ xcopy /s /y $(ProjectDir)Content $(SolutionDir)MyApplication.Web\Plugins\Device\Content\ xcopy /s /y $(ProjectDir)Scripts $(SolutionDir)MyApplication.Web\Plugins\Device\Scripts\
分別用於:清空刪除主Web項目插件目錄、拷貝視圖文件夾到主Web項目、拷貝樣式表文件夾到主Web項目、拷貝js文件夾到主Web項目。這樣就能實如今插件編譯經過後,自動將相應的插件文件複製到主Web項目的Plugins下,方便調試。this
每一個插件中都添加一個自啓動類(要求是靜態的)PluginStartUp,類中包含:插件名稱、初始化方法、Razor靜態文件導入擴展(css、js)。spa
1.自啓動類屬性插件
.Net Framework 4.0後提供了PreApplicationStartMethodAttribute屬性,提供對應用程序啓動的擴展支持。命令行
https://msdn.microsoft.com/zh-cn/library/system.web.preapplicationstartmethodattribute.aspx 調試
使用時,將PreApplicationStartMetod的聲明寫在自啓動類的命名空間前。
[assembly: System.Web.PreApplicationStartMethod(typeof(MyApplication.Plugins.Device.PluginStartUp), "Init")] namespace MyApplication.Plugins.Device { /// <summary> /// 插件自啓動類,用於註冊插件 /// </summary> public static class PluginStartUp { } }
2.插件名稱
插件名稱爲自啓動類的屬性,做爲本插件的惟一標識。
public static string Name { get { return "Device"; } }
3.插件初始化方法
初始化包括註冊路由和Razor視圖引擎。
將插件中的Controller註冊爲一個Area,主Web項目引用插件後就會把每個插件看成一個域。
註冊視圖引擎,主要是添加View的尋找路徑,即/Plugins/插件名稱/Views 路徑。
/// <summary> /// 插件初始化 /// </summary> public static void Init() { RegRoute(); RegViewEngine(); } /// <summary> /// 註冊視圖引擎 /// </summary> private static void RegViewEngine() { ViewEngines.Engines.Add(new RazorViewEngine { AreaViewLocationFormats = new[] { "~/Plugins/" + Name + "/Views/{1}/{0}.cshtml" } }); } /// <summary> /// 註冊插件路由 /// </summary> public static void RegRoute() { RouteTable.Routes.MapRoute( "Device", "/Device/{controller}/{action}/{id}", new { controller = "DeviceHome", action = "Index", id = UrlParameter.Optional }).DataTokens["area"] = Name; }
4.Razor擴展方法
在View頁面中引入css和js文件時,若是用插件中的相對路徑,在引入到主Web項目後則會找不到文件,所以須要提供一個導入css和js文件的Html擴展方法,在View頁面中使用該方法引入文件,方法內將路徑格式化。
/// <summary> /// 導入css, Razor Html擴展 /// </summary> /// <param name="helper"></param> /// <param name="cssName"></param> /// <returns></returns> public static IHtmlString ImportCss(this HtmlHelper helper, string cssName) { return helper.Raw(string.Format("<link href=\"/Plugins/{0}/Content/{1}\" type='text/css' rel='stylesheet' />", Name, cssName)); } /// <summary> /// 導入js, Razor Html擴展 /// </summary> /// <param name="helper"></param> /// <param name="jsName"></param> /// <returns></returns> public static IHtmlString ImportJs(this HtmlHelper helper, string jsName) { return helper.Raw(string.Format("<script src=\"/Plugins/{0}/Scripts/{1}\" ></script>", Name, jsName)); }
在View頁面內,使用這兩個擴展方法引入文件。
@Html.ImportCss("device.css") @Html.ImportJs("device.js")
以上就完成了原項目插件化的改造。主Web項目添加對插件的引用,當項目啓動時,PluginStartUp類自動運行完成插件初始化。
當有新項目個性化需求時,只需將插件複製一份,並修改插件內的controller、view、content、scripts等,Biz、Model都無需變化(前提是項目的主業務流程是一致的),主Web項目也無需變更,發佈時,根據項目的狀況,須要哪些插件就在Plugins下面保留哪些插件便可。