【ky开元棋盘网址】
简述 C# 中应用顺序集的装载进程
发布日期:2022-08-07 03:21    点击次数:81

本文转载自微信群众号「DotNET技能圈」,作者michaelscode。转载本文请联络DotNET技能圈群众号。

相识顺序集怎么在C#.NET中加载

我们一贯在处理惩罚库和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中:

class Program {     static void Main(string[] args)     {         int a = int.Parse(Console.ReadLine());         int b = int.Parse(Console.ReadLine());         Console.WriteLine("A + B = " + Add(a, b));     }      private static int Add(int a, int b)     {         var calculator = new Lib1.Calculator();         return calculator.Sum(a, b);     } } 

在Lib1中:

public class Calculator {     public int Sum(int a, int b)     {         return a + b;     } 

输入Main编制时,还没有加载Lib1顺序集。然则,在输入Add编制时,CLR查验测验剖析Calculator范例,找出它在引用的顺序集Lib1中,尔后查验测验加载该顺序集。

.NET中的顺序集绑定

当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。此进程称为“探测”。算法以下:

查抄文件夹[application base] / [assembly name].dll。应用顺序库是应用顺序可执行文件所在的职位地方。平日,您的Bin \ Debug或Bin \ Release文件夹。 查抄一下 [application base] / [assembly name] / [assembly name].dll 假设为引用的顺序集指定了地区性信息,则仅查抄下列目录: [application base] / [culture] / [assembly name].dll [application base] / [culture] / [assembly name] / [assembly name].dll 假设该 节点存在于设置文件中,则它将在该privatePath节点的属性指定的文件夹中查找顺序集。

他们为何要使全体事变变得云云费力,对吗?

理论上,这类逻辑极度有助于我们倒退,而不会使事变变得费力。它的存在是为了完成一些首要目标:

为了确保您引用的是特定的顺序集和版本,则将加载该切当版本。否则,将激发很是。并且,假设您晓得自身在做什么,则可以或许在设置文件中指定笼盖划定端方(绑定重定向)。 为了灵巧地在您要加载的顺序集及第行。譬如,假设要痛处差别的地区性(言语)加载差别的顺序集,则可以或许轻松地做到这一点。或许,假设您要痛处客户设置加载差别的顺序集,那也可以。 为了安好起见,我们应用了全称的顺序集。他们确保您不克不迭“伪造”顺序集。譬如,服务内容假设某个过程停留加载Lib1 v4.5,那末您将没法加载具有沟通名称和版本的恶意软件顺序集。加载时会激发很是。这就是为安在计算机上全体过程都同享的GAC只担任强名称顺序集的启事。

在大大都应用顺序中,您无需记着顺序集加载和探测的宏壮逻辑。您无需相识或推敲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部份的文件中增加下列几行:

<?xml version="1.0" encoding="utf-8" ?> <configuration>   ...   <runtime>     ...     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">       <dependentAssembly>         <assemblyIdentity name="log4net"                            publicKeyToken="669e0ddf0bb1aa2a" culture="neutral" />         <bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="1.2.0" />       </dependentAssembly>     </assemblyBinding>   </runtime>   ... </configuration

 这意味着,只有运行时想绑定到版才略域为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/

 



上一篇:Windows 11第三方Files文件打点器推出新版本:将原生支持AMR 64
下一篇:一个越活越优异的女士,每每会逼本身养成这几个好习性