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


目前在學習ASP.NET CORE MVC中,今天看到微軟在ASP.NET CORE MVC 2.0中又恢復了允許開發人員引用第三方DLL程序集的功能,感到甚是高興!於是我急忙寫了個Demo想試試,我的項目結構如下:

可以看到解決方案中就兩個項目,AspNetCoreWebApp就是一個ASP.NET CORE MVC 2.0的項目,而MyNetCoreLib是一個.Net Core 2.0的類庫項目,為了體現AspNetCoreWebApp是通過程序集來引用MyNetCoreLib的,我還在解決方案中創建了一個文件夾叫Reference,將類庫項目MyNetCoreLib編譯后生成的DLL文件放到了Reference文件夾中,然后在AspNetCoreWebApp中通過添加引用程序集的方式引用了MyNetCoreLib.dll,如下圖所示:

 

然后編譯整個解決方案,調試AspNetCoreWebApp這個項目,運行立馬報錯。。。錯誤如下:

 

這明顯是一個運行時錯誤,因我在編譯整個解決方案的時候是成功的,沒有報任何錯誤。后來去網上查了查資料,發現雖然我們在項目AspNetCoreWebApp中引用了MyNetCoreLib.dll,而且項目AspNetCoreWebApp編譯后也在其Bin目錄下輸出了MyNetCoreLib.dll這個文件,如下圖所示:

但是ASP.NET CORE MVC的依賴注入環境其實並不知道該到哪里去找MyNetCoreLib.dll這個文件,所以才會在運行時報出InvalidOperationException: Cannot find compilation library location for package 'MyNetCoreLib'這種錯誤。。。開發人員需要用代碼去告訴ASP.NET CORE MVC應該到哪里去找到MyNetCoreLib.dll這個文件。

 

因此首先我們需要定義一個叫MetadataReferenceFeatureProvider的類,代碼如下,其關鍵代碼就是告訴ASP.NET CORE MVC的依賴注入環境去AppDomain.CurrentDomain.BaseDirectory(也就是Bin目錄)下找我們在項目中引用的程序集文件

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方法中的代碼):

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,好了這下項目成功運行了,沒有報任何錯誤。

 

也不知道本文討論的這個問題是ASP.NET CORE MVC 2.0的一個缺陷,會在以后版本中修復,還是微軟故意為之?因為我試了下在.NET CORE 2.0的控制台項目中,直接引用第三方程序集DLL文件是完全沒問題的,不需要寫任何額外的代碼就可以使用。既然微軟在ASP.NET CORE MVC中也開放了引用第三方程序集這個功能,其實就完全可以把它做的和老.Net Framework一樣,自動去Bin目錄下面尋找DLL文件即可,希望ASP.NET CORE MVC以后的版本能夠完善這個功能,不再需要開發人員在引用DLL文件后,還要添加額外的代碼。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM