.Net Core利用反射动态加载类库的方法(解决类库不包含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
对于类库项目来说,通常会引用解决方案中其他通用项目,而主体程序也会引用这些通用项目,所以对于类库来说,在编译生成的文件中,并不需要这些文件。这种情况下,也需要修改.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类库加载自己需要的版本。
四、结尾
在.Net Core动态加载类库还是挺多坑的,以上是我踩过来,与大家分享~
参考文献:
.Net Core利用反射动态加载类库的方法(解决类库不包含Nuget依赖包的问题)的更多相关文章
- C# 利用反射动态加载dll
笔者遇到的一个问题,dll文件在客户端可以加载成功,在web端引用程序报错.解决方法:利用反射动态加载dll 头部引用加: using System.Reflection; 主要代码: Assembl ...
- java利用反射动态加载方法
@参考文章 根据特定字符串加载相应的方法,有人用if else,有人用switch.参数少了或情况少了还好,很多方法真要命,不要紧,java反射拯救你 import java.lang.reflect ...
- 利用“反射”动态加载R文件中的资源
前几天做一个Android下面数据库相关的应用.用ListVIew展示表中数据的时候我希望能给表中每一条记录,加一个展示的图片.但是用数据库保存图片是比较难搞的.于是就把所需图片都保存到res下的dr ...
- java反射并不是什么高深技术,面向对象语言都有这个功能,而且功能也很简单,就是利用jvm动态加载时生成的class对象
java反射并不是什么高深技术,面向对象语言都有这个功能. 面向对象语言都有这个功能,而且功能也很简单,就是利用jvm动态加载时生成的class对象,去获取类相关的信息 2.利用java反射可以调用类 ...
- 微信小程序(五) 利用模板动态加载数据
利用模板动态加载数据,其实是对上一节静态数据替换成动态数据:
- js实现动态加载脚本的方法实例汇总
本文实例讲述了js实现动态加载脚本的方法.分享给大家供大家参考,具体如下: 最近公司的前端地图产品需要做一下模块划分,希望用户用到哪一块的功能再加载哪一块的模块,这样可以提高用户体验. 所以到处查 ...
- Linux下C++动态加载so 调用方法
Windows 下的C++动态加载DLL调用方法 文献参考 http://man7.org/linux/man-pages/man0/dlfcn.h.0p.html http://man7.org/l ...
- java反射动态加载类Class.forName();
1,所有的new出来的对象都是静态加载的,在程序编译的时候就会进行加载.而使用反射机制Class.forName是动态加载的,在运行时刻进行加载. 例子:直接上两个例子 public class Ca ...
- 利用javascript动态加载头部出现点击事件与hover事件无效解决方法
这里是利用es6的promise函数来异步加载,当HTML动态加载过去的HTML片段加载完毕再执行绑定事件的js代码: 具体过程如下 这里是用了jQuery框架的例子 $(function(){ // ...
随机推荐
- ASP.NET Core:中间件
一.什么是中间件 我们都知道,任何的一个web框架都是把http请求封装成一个管道,每一次的请求都是经过管道的一系列操作,最终才会到达我们写的代码中.而中间件就是用于组成应用程序管道来处理请求和响应的 ...
- COM笔记-CoCreateInstance
CoCreateInstance 创建组件的最简单的方法是使用CoCreateInstance函数. 在COM库中包含一个用于创建组件的名为CoCreateInstance的函数.此函数需要一个CLS ...
- git 拉取代码指定分支
问题背景: 新项目还在开发阶段,没有正式对外发布,所以开发同事合并代码到develop上(或者其他名称分支上),而不是到master分支上 通过git拉取代码的时候,默认拉取的是master分支,如下 ...
- 常见递归&非递归实现
void my_strcpy(char *to,const char *from) { if('\0' == *from){ *to = '\0'; return ; } *to++ = *from+ ...
- 再也不用担心了,微软官方系统(win10为例)U盘安装教程
参考文章地址 使用微软官方工具安装纯净版操作系统. 一.准备工作 检查电脑规格是否支持安装(主要看看系统配置是否满足系统运行的最低要求) 一台联网电脑(不一定非是要装系统的那台): 一个≥8G 空间的 ...
- Go: 复合数据类型slice
slice slice 表示用于相同类型元素的可变长度的序列. slice有三个属性:指针.长度和容量. 指针:slice存储数据的内部结构是数组,指针指向的是数组的地址 长度:保存slice中的元素 ...
- go实现堆排序
package main import "fmt" func main(){ arr:=[]int{4,8,2,1,6,9,3,5,7,8,1,4} dui(arr) fmt.Pr ...
- ES6 class——音乐播放器实例
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- 20210717 noip18
考前 从小饭桌出来正好遇到雨下到最大,有伞但还是湿透了 路上看到一个猛男搏击暴风雨 到了机房收拾了半天才开始考试 ys 他们小饭桌十分明智地在小饭桌看题,雨下小了才来 考场 状态很差. 开题,一点想法 ...
- IKEv2协议协商流程: (IKE-SA-INIT 交换)第一包
文章目录 1. IKEv2 协商总体框架 2. 第一包流程图 3. openswan源码学习 3.1 ikev2parent_outI1() 3.2 ikev2parent_outI1_withsta ...