- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章简述 C# 中应用程序集的装载过程由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
我们一直在处理库和NuGet软件包。不管是好是坏,高级.NET开发人员都需要了解.NET运行时如何加载程序集.
这些库依赖于其他流行的库,并且有很多共享的依赖项。有了足够大的依赖关系网络,您最终将陷入冲突或困境。处理此类问题的最佳方法是了解该机制在内部的工作方式.
在本文中,您将看到.NET进程如何以及何时加载引用的程序集.
您将了解加载了哪个库版本,当有多个可用版本时会发生什么,以及为什么有时由于版本冲突而出现问题.
您将看到如何调试这些类型的问题,查看程序集绑定日志(融合日志)以及一些解决冲突的方法.
让我们从围绕.NET流程的一些基本术语开始.
一个装配在.NET是一个DLL或EXE文件。Visual Studio解决方案中的每个项目都被编译为一个程序集.
每个程序集可以包含多个模块,但是实际上,我们几乎总是在一个程序集中有一个模块,该模块的名称与该程序集相同.
在Visual Studio中启动进程或单击F5时,将执行启动项目程序集。除了.NET Framework或.NET Core程序集之外,它将是第一个加载的程序集.
之后,该过程将根据需要在运行时加载其他程序集。仅当需要调用该程序集的方法或使用该程序集的类型时,它才会延迟加载程序集.
这里是为一个简单的“ Hello World” .NET Framework项目加载的模块(出于我们所有的意图和目的,模块和程序集都是相同的)。MyStartup.dll是此处的启动项目:
.NET Core项目启动时加载的模块 。
当您从另一个项目引用一个项目时,在构建时,被引用项目的DLL或EXE被复制到启动项目的Bin文件夹中.
通常是Bin \ Debug或Bin \ Release。在运行时,当您第一次使用引用的项目中的类型时,CLR在应用程序目录中查找具有与期望的名称和版本相同的DLL文件。然后将程序集加载到流程中。这也称为绑定到装配件.
这是一个例子:
假设我们有一个名为MyStartup的简单控制台应用程序,它引用了另一个名为Lib1的项目。MyStartup使用Lib1程序集中的某些类.
在MyStartup中:
在Lib1中:
输入Main方法时,尚未加载Lib1程序集。但是,在输入Add方法时,CLR尝试解析Calculator类型,找出它在引用的程序集Lib1中,然后尝试加载该程序集.
当CLR需要加载程序集时,逻辑实际上比在Bin文件夹中查找要复杂一些。这是执行的实际逻辑(有关详细说明,请参见Microsoft文档[1]):
1.根据配置文件(app.config或web.config)确定需要加载的程序集的版本。该配置文件的名称为(在生成之后) [executable name].exe.config或web.config。绑定重定向在这里发挥了作用(稍后会详细介绍).
2.查看程序集是否已加载。如果加载了其他版本,则将抛出FileLoadException,除非它是一个可以同时加载多个版本的强命名程序集.
3.如果它是强名称程序集,请检查全局程序集缓存[2](GAC)。GAC是机器上共享多个应用程序部件的地方。如果需要的话,程序集会缓存。它只能存储强命名程序集。它可以存储同一程序集的不同版本。您可以使用gacutil.exe[3]自己将其安装到GAC .
4.如果它是一个强名称的程序集,并且配置文件包含 节点,那么它将检查那里的程序集位置。如果该 节点存在并且找不到程序集,FileNotFoundException则将引发a.
5.根据启发式算法检查程序集DLL或EXE。此过程称为“探测”。算法如下:
他们为什么要使所有事情变得如此困难,对吗?
实际上,这种逻辑非常有助于我们发展,而不会使事情变得困难。它的存在是为了实现一些重要目标:
在大多数应用程序中,您无需记住程序集加载和探测的复杂逻辑。您无需了解或考虑GAC,全名程序集或操作配置文件.
您几乎根本不需要考虑库的版本,因为可能的冲突通过称为“绑定重定向”的机制自动解决了.
如果有一件事对于了解这笔交易非常重要,那就是绑定重定向。能够告诉运行时它将实际加载哪个版本,而不管其引用的版本如何.
这是一个示例:您的流程有两个项目(模块):项目A和项目B。项目A引用log4net.dll v1.1,项目B引用log4net.dll v1.2。两个log4net DLL文件都复制到输出文件夹,但是只能有一个log4net.dll文件.
假设复制到输出文件夹的文件是log4net.dll v1.2。假设到达的第一个代码是Project A中的代码,该代码引用了log4net v1.1。运行时将在输出文件夹中查找,找到不同版本的log4net,并失败FileLoadException.
还有另一种可能。假设首先执行了项目B中的代码,并且在尝试使用log4net时,它成功加载了log4net.dll v1.2。片刻之后,Project A中的代码将尝试使用log4net v1.1,请参见该程序集已经加载了其他版本,并抛出FileLoadException.
如果您知道哪个log4net版本将在输出文件夹中,在这种情况下可以做的就是告诉运行时应该使用哪个版本。只需app.config在该runtime部分的文件中添加以下几行:
这意味着,只要运行时想绑定到版本范围为0.0.0.0to的程序集log4net 5.0.0.0,它就会尝试绑定到version 1.2.0.
实际上,您不必手动添加这些重定向,因为它们是自动添加的。如果转到启动项目的“属性”,则会看到以下设置:
图片-20200711101325128 。
默认情况下选中此选项。它会自动检测版本冲突并在.config文件中生成绑定重定向.
乍一看,绑定重定向可能看起来像是对所有问题的答案,但事实并非如此。使用绑定重定向时,基本上使用的库版本与预期不同。如果删除方法怎么办?或方法的签名已更改?在这种情况下,调用该方法时,程序将因运行时错误而失败。毕竟,创建版本是有原因的.
如果确实存在此类问题,则有解决方法。查看我的文章:如何解决.NET引用和NuGet软件包版本冲突[4].
当您有一个FileLoadException或类似的东西时,我建议做的第一件事是查看Visual Studio中的“模块”窗口。在这里,您将看到所有已加载的模块,并确定您要加载的程序集是否已加载,使用哪个版本以及从哪个路径加载.
除此之外,您还可以查看程序集绑定日志,也称为融合日志。这些日志将显示在程序集绑定尝试过程中到底发生了什么。您将看到运行时查找的程序集版本,运行时查找的文件夹以及故障点.
有几种查看融合日志的方法。首先,您必须启用它们,因为默认情况下它们是禁用的。您可以通过将HKLM\Software\Microsoft\Fusion\ForceLog值设置为1并将HKLM\Software\Microsoft\Fusion\LogPath值设置为来在注册表中手动启用它们C:\FusionLogs。日志将自动出现。或者,您可以使用Fusion Log Viewer,该软件应以方式安装在PC上fuslogvw.exe。我建议使用“一切窗口”搜索之[5]类的程序来查找它。确保以管理员权限运行融合日志查看器,以便能够启用和禁用日志。最近更流行的一种更现代的工具是Fusion ++[6].
也许您不需要,但是我以前讨厌不得不处理这类问题。例如一个逻辑上的问题,让我构建一些东西,甚至解决一个生产错误,但其他问题都好说,唯独这个…….
在这件事上别无选择,我不得不艰难地学习程序集绑定的内部工作。我发现,就像其他所有内容一样,一旦您理解了某些内容,它就会变得不那么可怕,甚至变得不再那么有趣了.
因此,我希望本文对您有意义,并会在我走过的道路上为您提供快速帮助.
References 。
[1] Microsoft文档: https://docs.microsoft.com/en-us/dotnet/framework/deployment/how-the-runtime-locates-assemblies 。
[2] 全局程序集缓存: https://docs.microsoft.com/en-us/dotnet/framework/app-domains/gac 。
[3] gacutil.exe: https://docs.microsoft.com/en-us/dotnet/framework/tools/gacutil-exe-gac-tool 。
[4] 如何解决.NET引用和NuGet软件包版本冲突: https://michaelscodingspot.com/how-to-resolve-net-reference-and-nuget-package-version-conflicts/ 。
[5] 一切窗口”搜索之: https://www.voidtools.com/ 。
[6] Fusion ++: https://github.com/awaescher/Fusion/ 。
原文链接:https://mp.weixin.qq.com/s/Axh9LD8tJYUtRNUcocty5Q 。
最后此篇关于简述 C# 中应用程序集的装载过程的文章就讲到这里了,如果你想了解更多关于简述 C# 中应用程序集的装载过程的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
C#内部访问修饰符的定义是内部:只能在包含程序集或友元程序集内访问。所以我的问题是什么是 C# 程序集?在包含程序集或 friend 程序集之内是什么意思?它是否意味着在同一个命名空间或项目中? 最佳
任何人都可以回答以下问题。我正在使用 c# 语言。 我可以将程序集调用为 .ddl 或 .exe 文件吗? 我可以将 Assembly Manifest 称为程序集吗? 程序集、元数据和程序集 lis
我正在从 Python 运行一个 .NET COM 程序集,只有当我将程序集 dll 和依赖项复制到我的 Python 根路径 c:\Python27 时才能使它正常工作。 这是不整洁的,所以我想将
作为世界上任何一名程序员,他/她一生中至少有一次,我正在尝试创建我的“革命性”,新的且唯一的操作系统。 :D 好吧,我正在使用虚拟模拟器(Oracle VM Virtual Box),为此我创建了一个
我创建了以下程序来读取 5 个数字,然后 dumpreg查看输入的数字... INCLUDE Irvine32.inc .data count = 5 scor
如何在保护模式下执行 IN 和 OUT 等受限指令? 我发现它需要足够高的特权级别(CPL)才能执行 IO 指令。我怎样才能在内核模式下运行,拥有 IO 权限或任何其他可能对我有帮助的东西? - 我希
目录 C# 程序集、模块和类型概念及关系 概述 程序集 模块 类型 程序集、模块和类型的关系 总结 引用
构建 maven assembly ,我留下了这样的东西: ${project.basedir} / LICENS
我的应用程序由几个核心程序集和几个扩展/插件程序集组成。为了让 MEF 知道插件必须提供的所有部件,即使我永远不会使用它们的任何部件,我也必须加载这些程序集。这使得应用程序需要更多时间来启动(如果我要
我对我们的构建基础结构有一个非常具体的要求,即将另一个 JAR 依赖项的一些内容复制到我的 Web 应用程序的特定子文件夹中。我们正在使用 maven-assembly-plugin,一个自然的方法是
为什么下面的指令会设置符号标志? mov al,0FEh sub al,2 据我了解,AL寄存器可以保存2^8 - 1或255。0FEh = 254(十进制)。减去 2 叶 252。这似乎是正数。 (
我以前使用过 NUnit,但已经有一段时间了,而且从来没有在这台机器上使用过。我在 Program Files 下解压了 2.4.8 版本,并且在尝试加载测试时不断收到此错误。 Could not l
我说的是一个使用 C# 进行游戏编程的小型游戏引擎。所以,我有一个嵌入单声道运行时的 C++ 应用程序(我称之为“启动器”)。我有一个用 C# 编写的程序集,它是我的游戏引擎类库。启动器按照 Embe
我对汇编相当陌生,并尝试从标准输入读取值(从 C 调用 scanf 函数)并将其打印回标准输出(使用 printf)。 .text readstr: .asciz "%d" #strin
谢谢帮助,我的问题是关于从下面的代码中收到的 ax 值? mov al,22h mov cl,0fdh imul cl 真机结果:ff9a 我的预期:00:9a(通过二进制相乘) 第一个数字是 22h
我正在开发一个汇编程序,该程序将整个文本文件读入缓冲区,然后将其显示在控制台中。它立即显示 24 行(每行的最大长度为 80,因为我使用 80 宽 * 25 高的 dossbox )然后等待用户输入,
我正在使用一个简单的程序集片段,使用 BIOS 作为引导加载程序的一部分将字符打印到屏幕上。这是引导加载程序代码。 [org 0x7c00] [bits 16] %include "a20_check
我只是想知道这段代码是什么意思: XOR EAX,EBX XOR EBX,EAX XOR EAX,EBX 最佳答案 那是 xor swapping . 在寄存器上执行它不会遇到常见的难看的失败案例。
我在新电脑上的 XNA 项目开始出现奇怪的错误。我有两个关于解决方案的项目和一个由它们使用的库。其中一个项目,一个 XNA 游戏项目,运行完美。另一个项目是 WindowsForm 和 XNA 的混合
是的,我正在努力实现类似的目标 __asm__(jmp label;); 其中 label 应替换为内存中保存的字符串值(结构体的字段)。 有没有办法做到这一点(或类似的方法可以让我跳转到运行时确定的
我是一名优秀的程序员,十分优秀!