简体   繁体   English

替代Assembly.LoadFile、Assembly.LoadFrom 和Assembly.Load?

[英]Alternative for Assembly.LoadFile, Assembly.LoadFrom and Assembly.Load?

I have two problems with a minimal, reproducible example that has three project targeting .NET Core 3.1.我有一个最小的、可重现的示例有两个问题,该示例具有三个面向 .NET Core 3.1 的项目。 But I also want to target .NET Standard 2.0 .但我也想以.NET Standard 2.0为目标。

The example is for an application that needs to load an assembly in run time and makes use of the provided assembly.该示例适用于需要在运行时加载程序集并使用提供的程序集的应用程序。

The assembly that is loaded references another project, which in turn makes use of a NuGet package.加载的程序集引用另一个项目,该项目反过来使用 NuGet 包。

Code代码

  • project Host is a Console Application that has no project references and no package references. project Host 是一个没有项目引用和包引用的控制台应用程序。 It contains the file Program.cs:它包含文件 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 is a Class Library that has a ProjectReference for ..\\Subfeature\\Subfeature.csproj and contains the file SomeFeature.cs: project Feature 是一个类库,它具有..\\Subfeature\\Subfeature.csproj的 ProjectReference 并包含文件 SomeFeature.cs:
public class SomeFeature
{
    public void PrintText()
    {
        System.Console.WriteLine(new SomeSubfeature().GetText());
    }
}
  • project Subfeature is a Class Library that has a PackageReference for Newtonsoft.Json and contains the file SomeSubfeature.cs: project Subfeature 是一个类库,它具有Newtonsoft.Json的 PackageReference 并包含文件 SomeSubfeature.cs:
public class SomeSubfeature
{
    public string GetText()
    {
        return Newtonsoft.Json.JsonConvert.SerializeObject("Some Text");
    }
}

Solved Problems解决的问题

  • The first solved problem is because the consumed assemblies reference another project and/or make use of packages.第一个解决的问题是因为使用的程序集引用了另一个项目和/或使用了包。 Assembly.LoadFrom only loads the requested assembly. Assembly.LoadFrom仅加载请求的程序集。 The referenced project's assembly and packages are not loaded.未加载引用项目的程序集和包。 This results in a FileNotFoundException because Subfeature could not be found.这会导致 FileNotFoundException,因为无法找到 Subfeature。

    I could solve this problem by (1) replacing Assembly.LoadFile(featurePath) with Assembly.LoadFrom(featurePath) so other required DLLs in the same directory can also be loaded.我可以解决通过更换这个问题(1) Assembly.LoadFile(featurePath)Assembly.LoadFrom(featurePath)以便在相同目录中的其他需要的DLL也可以被加载。 And (2) by making package DLLs that are only copied to the same directory during publish also get copied during build, by adding into Feature.csproj <PropertyGroup><CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies></PropertyGroup> .并且 (2) 通过添加到 Feature.csproj <PropertyGroup><CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies></PropertyGroup>使仅在发布期间复制到同一目录的包 DLL 在构建期间也被复制。

  • The second solved problem is that the application locks the DLLs while they are loaded.第二个解决的问题是应用程序在加载 DLL 时锁定它们。 This prevents me from deploying newer versions of the DLL's while the application is still running.这会阻止我在应用程序仍在运行时部署较新版本的 DLL。 It makes releasing newer versions cumbersome, when let's say, the application is part of an IIS hosted application.这使得发布新版本变得很麻烦,比如说,应用程序是 IIS 托管应用程序的一部分。 .NET Core no longer supports loading a shadow copy of a DLL. .NET Core 不再支持加载 DLL 的卷影副本。

    I could solve this problem by (1) replacing Assembly.LoadFile(featurePath) into Assembly.Load(System.IO.File.ReadAllBytes(featurePath)) so required DLLs are loaded from bytes that are read before loading.我可以通过 (1) 将Assembly.LoadFile(featurePath) ) 替换为Assembly.Load(System.IO.File.ReadAllBytes(featurePath))来解决这个问题,以便从加载之前读取的字节加载所需的 DLL。 And (2) having a filewatcher reload the application if something happens with a DLL file in its directory. (2) 如果其目录中的 DLL 文件发生问题,则让文件监视程序重新加载应用程序。

Final Problem最后的问题

The solution to the first problem is not compatible with the solution to the second problem.第一个问题的解决方案与第二个问题的解决方案不兼容。 Assembly.LoadFrom fixes my first problem. Assembly.LoadFrom解决了我的第一个问题。 Assembly.Load fixes my second problem. Assembly.Load解决了我的第二个问题。 But I haven't found an alternative for Assembly.LoadFile that fixes both problems at the same time.但是我还没有找到可以同时解决这两个问题的Assembly.LoadFile替代方案。

Add AssemblyResolve event handler to AppDomain.CurrentDomain and handle assembly loading as you do with reading all bytes.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;
        }

A side note: You need to provide full name for type else it will throw error.旁注:您需要提供类型的全名,否则会引发错误。 Like: "Dependency.DependentClass"比如: "Dependency.DependentClass"

Dependency assembly has 2 dependencies one is Newtonsoft.Json NuGet package, the other one is another project.依赖程序集有 2 个依赖项,一个是Newtonsoft.Json NuGet 包,另一个是另一个项目。 Bar class resides in another project. Bar类驻留在另一个项目中。

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

        public string AnotherProperty { get; set; }

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

EDIT: After the downvote, I looked up the above solution again and although it works it seems more likely a . net Framework编辑:在downvote之后,我再次查找了上述解决方案,虽然它有效,但似乎更可能是. net Framework . net Framework kind of a solution rather than a .net Core So a more . net Core . net Framework是一种解决方案,而不是.net Core所以更多. net Core . net Core like solution is to use a AssemblyLoadContext . . 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());
       
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM