標題:從零開始實現ASP.NET Core MVC的插件式開發(一) - 使用Application Part動態加載控制器和視圖
做者:Lamond Lu
地址:https://www.cnblogs.com/lwqlun/p/11137788.html
源代碼:https://github.com/lamondlu/Mystiquehtml
若是你使用過一些開源CMS的話,確定會用過其中的的插件化功能,用戶能夠經過啓用或者上傳插件包的方式動態添加一些功能,那麼在ASP.NET Core MVC中如何實現插件化開發呢,下面咱們來探究一下。git
本系列只是筆者的一些嘗試,並不表示必定正確,只是爲了分享一些思路,你們能夠一塊兒討論一下,後續會不斷更新。github
在ASP.NET Core中進行插件話開發,就不得不說ApplicationPart
。 ApplicationPart
是ASP.NET Core一個重要組件,它是應用程序資源的一種抽象,經過它能夠發現程序集中包含的控制器、視圖組件、TagHelper和預編譯Razor視圖等MVC功能。數據庫
默認狀況下,當一個ASP.NET Core MVC應用啓動時,它只會嘗試在當前應用啓動的項目及引用的項目中加載控制器,若是想從未直接引用的程序集中加載控制器和預編譯Razor視圖,咱們就須要藉助ApplicationPart
了。c#
而ASP.NET Core MVC中,有一個ApplicaitonPartManager
類, 經過ApplicationPartManager
咱們能夠來配置當前應用中使用哪一些ApplicationPart
。瀏覽器
例:cookie
var assembly = Assembly.LoadFile("demo.dll"); var assemblyPart = new AssemblyPart(assembly); var mvcBuilders = services.AddMvc(); mvcBuilders.ConfigureApplicationPartManager(apm => { apm.ApplicationParts.Add(assemblyPart); });
下面呢,咱們經過一個最簡單的實例,給你們演示一下如何藉助ApplicationPart
,動態加載第三方程序集中的控制器和預編譯視圖。mvc
首先咱們建立一個ASP.NET Core MVC的站點,命名爲DynamicPluginsDemoSiteapp
而後咱們同時建立一個.NET Core Class Library項目,命名爲DemoPlugin1, 同時對該項目引用ui
注意: 針對以上3個程序集,須要保證DynamicPluginsDemoSite和DemoPluigin1使用的相同的版本。
這裏爲了保證Razor視圖的預編譯,咱們須要打開DemoPlugin1項目的工程文件DemoPlugin1.csproj。將項目使用的SDK從"Microsoft.NET.Sdk"改成"Microsoft.Net.Sdk.Razor"。
<Project Sdk="Microsoft.NET.Sdk.Razor"> <PropertyGroup> <TargetFramework>netcoreapp2.2</TargetFramework> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <OutputPath>C:\Users\Lamond Lu\source\repos\DynamicPlugins\DynamicPluginsDemoSite\bin\Debug</OutputPath> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Razor" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" /> </ItemGroup> </Project>
注:若是不作此修改,最後項目編譯以後,不會產生預編譯的Razor視圖程序集。(這裏若是有其餘更優雅的修改方式,請你們留言, 我後續會先嚐試先編寫一個項目模板來避免這個重複操做)。
下面咱們開始編寫咱們的插件。
這裏咱們首先建立一個Plugin1Controller.cs
.
public class Plugin1Controller : Controller { public IActionResult HelloWorld() { return View(); } }
而後咱們添加一個對應的視圖文件HelloWorld.cshtml。
@{ } <h1>This is Demo Plugin1.</h1>
最終項目文件目錄以下:
最後咱們須要修改一個項目的輸出目錄,咱們須要將項目編譯的dll發送到DynamicPluginsDemoSite項目的Debug目錄中。
以上咱們就完成了第一個組件的全部修改,下面咱們開始修改DynamicPluginsDemoSite項目。
因爲DynamicPluginsDemoSite項目不能直接引用DemoPlugin1, 因此當項目啓動時,不能自主發現DemoPlugin1項目中的控制器,因此這裏咱們須要使用ApplicationPart
將DemoPlugin1的程序集加載到當前的運行環境中。
public void ConfigureServices(IServiceCollection services) { services.Configure<CookiePolicyOptions>(options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request. options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); var assembly = Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + "DemoPlugin1.dll"); var mvcBuilders = services.AddMvc(); var controllerAssemblyPart = new AssemblyPart(assembly); mvcBuilders.ConfigureApplicationPartManager(apm => { apm.ApplicationParts.Add(controllerAssemblyPart); }); mvcBuilders.SetCompatibilityVersion(CompatibilityVersion.Version_2_2); }
代碼解釋:
Assembly.LoadFile
方法將它加載。AssemblyPart
類,將加載程序集封裝成一個ApplicationPart
.mvcBuilders
對象的ConfigureApplicationPartManager
方法能夠用來配置當前項目中使用的ApplicationPart加載完控制器以後,咱們還須要加載插件的預編譯Razor視圖。這裏和以前的稍有不一樣,咱們須要使用CompileRazorAssemblyPart
來封裝加載的預編譯Razor視圖。
public void ConfigureServices(IServiceCollection services) { services.Configure<CookiePolicyOptions>(options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request. options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); var assembly = Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + "DemoPlugin1.dll"); var assemblyView = Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + "DemoPlugin1.Views.dll"); var viewAssemblyPart = new CompiledRazorAssemblyPart(assemblyView); var controllerAssemblyPart = new AssemblyPart(assembly); var mvcBuilders = services.AddMvc(); mvcBuilders.ConfigureApplicationPartManager(apm => { apm.ApplicationParts.Add(controllerAssemblyPart); apm.ApplicationParts.Add(viewAssemblyPart); }); mvcBuilders.SetCompatibilityVersion(CompatibilityVersion.Version_2_2); }
如今咱們啓動DynamicPluginsDemoSite,在瀏覽器中輸入/Plugin1/HelloWorld, 咱們的插件就正常啓用了。
注意:在啓動DynamicPluginsDemoSite站點以前,請務必先編譯DemoPlugin1項目,這樣DemoPlugin1產生的程序集纔會輸出到DynamicPluginsDemoSite中。
以上只是實現了一個最簡單的MVC插件功能,要想完善整個項目,後續還有不少工做要作
後續我會慢慢實現以上功能,你們敬請期待。