gpt4 book ai didi

c# - Assembly.LoadFile、Assembly.LoadFrom 和 Assembly.Load 的替代方案?

转载 作者:行者123 更新时间:2023-12-04 15:35:41 44 4
gpt4 key购买 nike

我有一个最小的、可重现的示例有两个问题,该示例具有三个针对 .NET Core 3.1 的项目。但我也想以 .NET Standard 2.0 为目标。

该示例适用于需要在运行时加载程序集并使用提供的程序集的应用程序。

加载的程序集引用了另一个项目,该项目又使用了 NuGet 包。

代码

  • project Host 是一个没有项目引用和包引用的控制台应用程序。它包含文件 Program.cs:
class Program
{
static void Main(string[] args)
{
var featurePath = System.IO.Path.GetFullPath(@"..\..\..\..\Feature\bin\Debug\netcoreapp3.1\Feature.dll");
var featureAssembly = System.Reflection.Assembly.LoadFile(featurePath);
var featureType = featureAssembly.GetType("SomeFeature");
var featureInstance = System.Activator.CreateInstance(featureType);
featureType.InvokeMember("PrintText",
System.Reflection.BindingFlags.InvokeMethod, null, featureInstance, new object[0]);
}
}
  • project Feature 是一个类库,它具有 ..\Subfeature\Subfeature.csproj 的 ProjectReference并包含文件 SomeFeature.cs:
public class SomeFeature
{
public void PrintText()
{
System.Console.WriteLine(new SomeSubfeature().GetText());
}
}
  • 项目子功能是一个类库,它具有 Newtonsoft.Json 的 PackageReference并包含文件 SomeSubfeature.cs:
public class SomeSubfeature
{
public string GetText()
{
return Newtonsoft.Json.JsonConvert.SerializeObject("Some Text");
}
}

已解决的问题

  • 第一个解决的问题是因为使用的程序集引用了另一个项目和/或使用了包。 Assembly.LoadFrom仅加载请求的程序集。未加载引用项目的程序集和包。这会导致 FileNotFoundException,因为找不到子特征。

    我可以通过 (1) 替换 Assembly.LoadFile(featurePath) 来解决这个问题与 Assembly.LoadFrom(featurePath)因此也可以加载同一目录中的其他所需的 DLL。并且 (2) 通过添加到 Feature.csproj <PropertyGroup><CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies></PropertyGroup> 中,使仅在发布期间复制到同一目录的包 DLL 在构建期间也被复制。 .

  • 第二个解决的问题是应用程序在加载 DLL 时锁定它们。这使我无法在应用程序仍在运行时部署更新版本的 DLL。它使发布较新版本变得很麻烦,比方说,该应用程序是 IIS 托管应用程序的一部分。 .NET Core 不再支持加载 DLL 的卷影副本。

    我可以通过 (1) 替换 Assembly.LoadFile(featurePath) 来解决这个问题进入Assembly.Load(System.IO.File.ReadAllBytes(featurePath))因此所需的 DLL 是从加载前读取的字节加载的。 (2) 如果目录中的 DLL 文件出现问题,让 filewatcher 重新加载应用程序。

最后的问题

第一个问题的解决方案与第二个问题的解决方案不兼容。 Assembly.LoadFrom解决了我的第一个问题。 Assembly.Load解决了我的第二个问题。但是我还没有找到 Assembly.LoadFile 的替代品可以同时解决这两个问题。

最佳答案

AssemblyResolve 事件处理程序添加到 AppDomain.CurrentDomain 并像读取所有字节一样处理程序集加载。

        const string location = @"..\..\..\..\Dependency\bin\Debug\netcoreapp3.1\";
static void Main(string[] args)
{
var domain = AppDomain.CurrentDomain;
domain.AssemblyResolve += Domain_AssemblyResolve;
var type = Type.GetType("Dependency.DependentClass,Dependency, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
var obj = Activator.CreateInstance(type);
Console.WriteLine(obj.ToString());
}

private static Assembly Domain_AssemblyResolve(object sender, ResolveEventArgs args)
{
var dll = $"{args.Name.Split(",")[0]}.dll";
var path = Path.Combine(location, dll);
var asm = Assembly.Load(File.ReadAllBytes(path));
return asm;
}

旁注:您需要为类型提供全名,否则会抛出错误。喜欢:“Dependency.DependentClass”

依赖程序集有2个依赖,一个是Newtonsoft.Json NuGet包,另一个是另一个项目。 Bar 类驻留在另一个项目中。

 public class DependentClass
{
public int MyProperty { get; set; }

public string AnotherProperty { get; set; }

public override string ToString()
{
return JsonConvert.SerializeObject(new Bar());
}
}

编辑: 否决票后,我再次查找上述解决方案,虽然它有效,但似乎更像是 。 net Framework 一种解决方案而不是 .net Core所以一个更多的。 net Core 之类的解决方案是使用 AssemblyLoadContext .

Define a custom assembly load context.

public class CustomLoadContext : AssemblyLoadContext
{
private readonly AssemblyDependencyResolver resolver;

public CustomLoadContext(string mainAssemblyToLoadPath) : base(isCollectible: true)
{
resolver = new AssemblyDependencyResolver(mainAssemblyToLoadPath);
}


protected override Assembly Load(AssemblyName name)
{
Console.WriteLine("Resolving : {0}",name.FullName);
var assemblyPath = resolver.ResolveAssemblyToPath(name);
if (assemblyPath != null)
{
return Assembly.Load(File.ReadAllBytes(assemblyPath));
}

return Assembly.Load(name);
}
}

Load your assembly and let the custom loader context to load it's dependencies.

        const string location = @"..\..\..\..\Dependency\bin\Debug\netcoreapp3.1\";

static void Main(string[] args)
{
var fullPath = Path.GetFullPath(location + "Dependency.dll");
var clx = new CustomLoadContext(fullPath); // initialize custom context
var asm = clx.LoadFromStream(new MemoryStream(File.ReadAllBytes(fullPath))); // load your desired assembly
var ins = asm.CreateInstance("Dependency.DependentClass");
Console.WriteLine(ins.ToString());

}

关于c# - Assembly.LoadFile、Assembly.LoadFrom 和 Assembly.Load 的替代方案?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59865067/

44 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com