zoukankan      html  css  js  c++  java
  • ASP.NET CORE MVC 2.0 项目中引用第三方DLL报错的解决办法

    目前在学习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文件后,还要添加额外的代码。

  • 相关阅读:
    zz--Add-Migration与EF及Mysql的使用。。
    最后学期
    E. Tree Queries 题解(思维+dfs序)
    D. 0-1 MST 题解(补图的联通块)
    F. Equalizing Two Strings 题解(思维)
    CSUST 白银御行想展示 题解(思维)
    E2. Rubik's Cube Coloring (hard version) 题解(dp+思维)
    D. Hemose in ICPC ? 题解(二分+dfs序+交互)
    C. Bakry and Partitioning 题解(思维+两次dfs)
    E. Bored Bakry 题解(二进制+思维)
  • 原文地址:https://www.cnblogs.com/OpenCoder/p/8052693.html
Copyright © 2011-2022 走看看