目前在學習ASP.NET CORE MVC中,今天看到微軟在ASP.NET CORE MVC 2.0中又恢復了容許開發人員引用第三方DLL程序集的功能,感到甚是高興!因而我急忙寫了個Demo想試試,個人項目結構以下:app
能夠看到解決方案中就兩個項目,AspNetCoreWebApp就是一個ASP.NET CORE MVC 2.0的項目,而MyNetCoreLib是一個.Net Core 2.0的類庫項目,爲了體現AspNetCoreWebApp是經過程序集來引用MyNetCoreLib的,我還在解決方案中建立了一個文件夾叫Reference,將類庫項目MyNetCoreLib編譯後生成的DLL文件放到了Reference文件夾中,而後在AspNetCoreWebApp中經過添加引用程序集的方式引用了MyNetCoreLib.dll,以下圖所示:ide
而後編譯整個解決方案,調試AspNetCoreWebApp這個項目,運行立馬報錯。。。錯誤以下:學習
這明顯是一個運行時錯誤,因我在編譯整個解決方案的時候是成功的,沒有報任何錯誤。後來去網上查了查資料,發現雖然咱們在項目AspNetCoreWebApp中引用了MyNetCoreLib.dll,並且項目AspNetCoreWebApp編譯後也在其Bin目錄下輸出了MyNetCoreLib.dll這個文件,以下圖所示:fetch
可是ASP.NET CORE MVC的依賴注入環境其實並不知道該到哪裏去找MyNetCoreLib.dll這個文件,因此纔會在運行時報出InvalidOperationException: Cannot find compilation library location for package 'MyNetCoreLib'這種錯誤。。。開發人員須要用代碼去告訴ASP.NET CORE MVC應該到哪裏去找到MyNetCoreLib.dll這個文件。ui
所以首先咱們須要定義一個叫MetadataReferenceFeatureProvider的類,代碼以下,其關鍵代碼就是告訴ASP.NET CORE MVC的依賴注入環境去AppDomain.CurrentDomain.BaseDirectory(也就是Bin目錄)下找咱們在項目中引用的程序集文件this
using Microsoft.AspNetCore.Mvc.ApplicationParts; using Microsoft.AspNetCore.Mvc.Razor.Compilation; using Microsoft.CodeAnalysis; using Microsoft.Extensions.DependencyModel; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection.PortableExecutable; using System.Threading.Tasks; namespace AspNetCoreWebApp.Utils { public class ReferencesMetadataReferenceFeatureProvider : IApplicationFeatureProvider<MetadataReferenceFeature> { public void PopulateFeature(IEnumerable<ApplicationPart> parts, MetadataReferenceFeature feature) { var libraryPaths = new HashSet<string>(StringComparer.OrdinalIgnoreCase); foreach (var assemblyPart in parts.OfType<AssemblyPart>()) { var dependencyContext = DependencyContext.Load(assemblyPart.Assembly); if (dependencyContext != null) { foreach (var library in dependencyContext.CompileLibraries) { if (string.Equals("reference", library.Type, StringComparison.OrdinalIgnoreCase)) { foreach (var libraryAssembly in library.Assemblies) { //告訴ASP.NET CORE MVC若是如今項目中有引用第三方程序集,要到AppDomain.CurrentDomain.BaseDirectory這個文件夾(就是Bin目錄)下去尋找該程序集的dll文件 libraryPaths.Add(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, libraryAssembly)); } } else { foreach (var path in library.ResolveReferencePaths()) { libraryPaths.Add(path); } } } } else { libraryPaths.Add(assemblyPart.Assembly.Location); } } foreach (var path in libraryPaths) { feature.MetadataReferences.Add(CreateMetadataReference(path)); } } private static MetadataReference CreateMetadataReference(string path) { using (var stream = File.OpenRead(path)) { var moduleMetadata = ModuleMetadata.CreateFromStream(stream, PEStreamOptions.PrefetchMetadata); var assemblyMetadata = AssemblyMetadata.Create(moduleMetadata); return assemblyMetadata.GetReference(filePath: path); } } } }
其次咱們還要在項目AspNetCoreWebApp的Startup.cs文件中的services.AddMvc()方法上註冊咱們定義的這個Provider,代碼以下(注意ConfigureServices方法中的代碼):spa
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.AspNetCore.Mvc.Razor.Compilation; using AspNetCoreWebApp.Utils; namespace AspNetCoreWebApp { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddMvc().ConfigureApplicationPartManager(manager => { //移除ASP.NET CORE MVC管理器中默認內置的MetadataReferenceFeatureProvider,該Provider若是不移除,仍是會引起InvalidOperationException: Cannot find compilation library location for package 'MyNetCoreLib'這個錯誤 manager.FeatureProviders.Remove(manager.FeatureProviders.First(f => f is MetadataReferenceFeatureProvider)); //註冊咱們定義的ReferencesMetadataReferenceFeatureProvider到ASP.NET CORE MVC管理器來代替上面移除的MetadataReferenceFeatureProvider manager.FeatureProviders.Add(new ReferencesMetadataReferenceFeatureProvider()); }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseBrowserLink(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); } } }
而後從新編譯代碼,調試項目AspNetCoreWebApp,好了這下項目成功運行了,沒有報任何錯誤。3d
也不知道本文討論的這個問題是ASP.NET CORE MVC 2.0的一個缺陷,會在之後版本中修復,仍是微軟故意爲之?由於我試了下在.NET CORE 2.0的控制檯項目中,直接引用第三方程序集DLL文件是徹底沒問題的,不須要寫任何額外的代碼就可使用。既然微軟在ASP.NET CORE MVC中也開放了引用第三方程序集這個功能,其實就徹底能夠把它作的和老.Net Framework同樣,自動去Bin目錄下面尋找DLL文件便可,但願ASP.NET CORE MVC之後的版本可以完善這個功能,再也不須要開發人員在引用DLL文件後,還要添加額外的代碼。調試