ASP.NET CORE MVC 2.0 項目中引用第三方DLL報錯的解決辦法 - InvalidOperationException: Cannot find compilation library

目前在學習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文件後,還要添加額外的代碼。調試

相關文章
相關標籤/搜索