首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >替代Assembly.LoadFile,Assembly.LoadFrom和Assembly.Load?

替代Assembly.LoadFile,Assembly.LoadFrom和Assembly.Load?
EN

Stack Overflow用户
提问于 2020-01-22 17:19:52
回答 1查看 4K关注 0票数 3

我有两个问题,一个最小的,可重复的例子,有三个项目针对.NET核心3.1。但我也想以.NET Standard2.0为目标。

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

加载的程序集引用另一个项目,该项目反过来使用NuGet包。

代码

  • 项目主机是一个没有项目引用和包引用的控制台应用程序。它包含文件Program.cs:

代码语言:javascript
复制
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]);
    }
}

SomeFeature.cs:项目特性是一个类库,它具有用于..\Subfeature\Subfeature.csproj的ProjectReference,并包含文件..\Subfeature\Subfeature.csproj

代码语言:javascript
复制
public class SomeFeature
{
    public void PrintText()
    {
        System.Console.WriteLine(new SomeSubfeature().GetText());
    }
}

  • 项目子功能是一个类库,它具有用于Newtonsoft.Json的PackageReference并包含文件Newtonsoft.Json

代码语言:javascript
复制
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)通过使发布过程中只复制到同一个目录的包DLL在构建过程中也会被复制,从而添加到Feature.csproj <PropertyGroup><CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies></PropertyGroup>中。

  • 第二个解决的问题是,应用程序在加载DLL时锁定它们。这使我无法在应用程序仍在运行时部署较新版本的DLL。当我们假设应用程序是IIS宿主应用程序的一部分时,它使得发布新版本变得非常麻烦。.NET核心不再支持加载DLL.

的影子副本。

我可以通过(1)将Assembly.LoadFile(featurePath)替换为Assembly.Load(System.IO.File.ReadAllBytes(featurePath))来解决这个问题,以便从加载前读取的字节中加载所需的DLL。(2)如果目录中的DLL文件发生了什么变化,那么让一个文件程序重新加载应用程序。

最终问题

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-01-26 15:20:31

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

代码语言:javascript
复制
        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"

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

代码语言:javascript
复制
 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

定义自定义程序集加载上下文。

代码语言:javascript
复制
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);
        }
    }

加载程序集并让自定义加载器上下文加载它的依赖项。

代码语言:javascript
复制
        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());
       
        }
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59865067

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档