ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

.Net 6 EnableDynamicLoading利用反射动态加载DLL类库的方法(解决类库不包含Nuget依赖包的问题)

2021-12-19 20:01:09  阅读:195  来源: 互联网

标签:类库 文件 项目 DLL Nuget using 动态 加载


.Net Core利用反射动态加载DLL类库的方法(解决类库不包含Nuget依赖包的问题)

 

  在.Net Framework时代,生成类库只需将类库项目编译好,然后拷贝到其他项目,即可引用或动态加载,相对来说,比较简单。但到了.Net Core时代,动态加载第三方类库,则稍微麻烦一些。

一、类库发布丢失Nuget依赖包   

   对于大部分类库来说,项目或多或少会引用第三方程序集,特别是Nuget程序包。通常编译类库项目生成的文件中,并不会包含引用的Nuget包相关类库,而是通过*.deps.json文件来描述类库所需的依赖。这样造成一种问题,如果该类库是通过动态加载的方式引用,则程序运行时,会提示“缺少某某dll”的问题。

  解决上述问题,需要在该类库项目的.csproj文件中,在<PropertyGroup></PropertyGroup>标签中加入<EnableDynamicLoading>true</EnableDynamicLoading>标志,该属性将告诉编译器,该项目是动态加载的组件。相关链接:https://docs.microsoft.com/zh-cn/dotnet/core/project-sdk/msbuild-props#enabledynamicloading

二、类库编译生成多余的dll

  对于类库项目来说,通常会引用解决方案中其他通用项目,而主体程序也会引用这些通用项目,所以对于类库来说,在编译生成的文件中,并不需要这些文件。比如主体程序A和动态类库项目B,共同引用通用项目C,C项目又有很多第三方类库的引用,那么在编译生成动态类库B的时候,会带上项目C及其相关依赖的文件,但实际上,对于动态类库项目B来说,是不需要的。这种情况下,也需要修改.csproj项目文件,如下图,生成的类库文件将不会包含pluginBase.csproj类库及其所有的依赖;

三、利用反射动态加载类库

  如果按照文末参考文献中的教程,我尝试过仍会出现找不到“某某.dll”的问题,这边贴出我的代码,供参考:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.IO;
 4 using System.Reflection;
 5 using System.Runtime.Loader;
 6 
 7 namespace LoadDLL
 8 {
 9     /// <summary>
10     /// 程序集加载器
11     /// </summary>
12     public class AssemblyLoader
13     {
14         private string _basePath;
15         private AssemblyLoadContext context;
16 
17 
18         public AssemblyLoader(string basePath)
19         {
20             _basePath = basePath;
21         }
22 
23         public Type Load(string dllFileName, string typeName)
24         {
25                 context = new AssemblyLoadContext(dllFileName);
26                 context.Resolving += Context_Resolving;
27                 //需要绝对路径
28                 string path = Path.Combine(_basePath, dllFileName);
29                 if (File.Exists(path))
30                 {
31                     try
32                     {
33                         using (var stream = File.OpenRead(path))
34                         {
35                             Assembly assembly = context.LoadFromStream(stream);
36                             Type type = assembly.GetType(typeName);
37                             dicTypes.Add(typeName, type);
38                             return type;
39                         }
40                     }
41                     catch (Exception ex)
42                     {
43                         Console.WriteLine($"加载节点{dllFileName}-{typeName}发生异常:{ex.Message},{ex.StackTrace}");
44                     }
45 
46                 }
47                 else
48                 {
49                     Console.WriteLine($"节点动态库{dllFileName}不存在:{path}");
50                 }            
51             return null;
52         }
53 
54         /// <summary>
55         /// 加载依赖文件
56         /// </summary>
57         /// <param name="context"></param>
58         /// <param name="assemblyName"></param>
59         /// <returns></returns>
60         private Assembly Context_Resolving(AssemblyLoadContext context, AssemblyName assemblyName)
61         {
62             string expectedPath = Path.Combine(_basePath, assemblyName.Name + ".dll"); ;
63             if (File.Exists(expectedPath))
64             {
65                 try
66                 {
67                     using (var stream = File.OpenRead(expectedPath))
68                     {
69                         return context.LoadFromStream(stream);
70                     }
71                 }
72                 catch (Exception ex)
73                 {
74                     Console.WriteLine($"加载节点{expectedPath}发生异常:{ex.Message},{ex.StackTrace}");
75                 }
76             }
77             else
78             {
79                 Console.WriteLine($"依赖文件不存在:{expectedPath}");
80             }
81             return null;
82         }
83     }
84 }

其中Context_Resolving(),是用于加载类库文件过程中,处理触发加载相关依赖文件的事件的方法,通过上述代码,可以保证将类库的完整地动态加载进程序,并且不会与其他动态加载类库项目发生程序集冲突的问题:比如A类库和B类库都有共同的依赖C,但两者的引用的C版本不同,通过AssemblyLoadContext可以保证A/B类库加载自己需要的版本。

四、调试DLL

  在主体程序运行中,通常不会进入类库代码中的断点,这对类库调试带来一定麻烦了。这时候需要对类库的生成作进一步的设置,方法如下图,拷贝类库及其所有依赖文件时,注意要带上相应的.pdb文件

 

 

五、结尾

  在.Net Core动态加载类库还是挺多坑的,以上是我踩过来,与大家分享~

 

参考文献:

1、使用插件创建 .NET Core 应用程序

标签:类库,文件,项目,DLL,Nuget,using,动态,加载
来源: https://www.cnblogs.com/Leo_wl/p/15708371.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有