在Startup.cs中加载程序集 .net core 2.1

4
我有一个叫做nuqkgs的文件夹,里面装着nugget包。在项目启动时,我想要将这些包(也就是dll文件)加载到项目中,以便在运行时使用。我使用以下代码来加载它们,在调试时可以看到信息和dll已被找到并打开,但当应该使用它们时,会出现dll无法找到的错误,并且我可以看到解决方案试图在bin文件夹中查找它们(它们位于解决方案/nuqkgs/中)。我不想在任何文件中注册这些包,我只想能够把nugget包放入nuqkgs文件夹中并自动注册它们。有什么想法或者有谁在core 2.1中做过这个吗?这是我的startup.cs:
    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<CookiePolicyOptions>(options =>
        {
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        });

        IList<Assembly> components = new List<Assembly>();
        foreach (string file in Directory.EnumerateFiles(@"C:\Users\myName\source\repos\core2.1test\core2.1test\nuqkgs\", "*.nupkg", SearchOption.AllDirectories))
        {
            using (ZipArchive nuget = ZipFile.Open(file, ZipArchiveMode.Read))
            {
                foreach (ZipArchiveEntry entry in nuget.Entries)
                {
                    if (entry.Name.Contains(".dll"))
                    {
                        using (BinaryReader reader = new BinaryReader(entry.Open()))
                        {
                            components.Add(Assembly.Load(reader.ReadBytes((int)entry.Length)));
                        }
                    }
                }
            }
        }

        services.AddMvc()
          .ConfigureApplicationPartManager(apm =>
          {
              foreach (var c in components)
              {
                  var part = new AssemblyPart(c);
                  var des = part.Assembly.Location.ToString();
                  apm.ApplicationParts.Add(part);
              }
          }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
 }

这只是一个整体上非常糟糕的计划。我理解你的想法,但动态引用只会让你的代码变得非常复杂。首先,你必须全程动态化,这意味着使用任何这些动态加载的程序集的所有代码也必须通过反射来调用。你的代码只会成为一堆字符串引用,并且会很脆弱,所有的错误都将是运行时错误,而不是像你实际想要的编译时错误。 - Chris Pratt
这将用于插件化架构的解决方案,因此在将其放入文件夹之前,所有错误都将在各个组件的编译中捕获。 - Johann Guðjónsson
抱歉,有几件事情我不太明白,Nugget 和这个有什么关系呢?您打算实时添加 DLL 还是只是每次启动时添加一次? - Filip Cordas
正如您在代码中所看到的,有一个文件夹里面有一个NuGet包,我会提取该NuGet包并注册和使用每个包中的DLL。如果我们将另一个NuGet包添加到文件夹中,我们需要重新启动应用程序,以便进行注册。 - Johann Guðjónsson
不行。根据定义,你是在运行时加载程序集,所以绝对没有办法在编译时捕获错误。在编译期间,应用程序将不知道任何此代码或引用的存在。 - Chris Pratt
显示剩余4条评论
2个回答

2
根据AssemblyLoadContext文档所述,Assembly.Load(byte[])会在新的未命名加载上下文中加载程序集,并且AssemblyLoadContext(默认之外的)目前无法解析依赖项。这可能是你的部件不起作用的原因。尝试使用AssemblyLoadContext.Default.LoadFromStream而不是Assembly.Load(byte[])

0

我已经让它工作了,现在我使用的方法是:

  1. 打开NuGet中的每个DLL文件,并将其写入磁盘上的文件。
  2. 在内存流中打开文件并将其读入内存,然后可以在我的应用程序中使用它。

或者你也可以使用以下步骤2:

AssemblyLoadContext.Default.LoadFromAssemblyPath(createPathSource);

这样你在解决方案中使用它时就可以引用 dll 文件了。

    public void ConfigureServices(IServiceCollection services)
    {
        IList<Assembly> components = new List<Assembly>();

        foreach (string file in Directory.EnumerateFiles(@"C:\Users\userName\source\repos\core2.1test\core2.1test\nuqkgs\", "*.nupkg", SearchOption.AllDirectories))
        {
            using (ZipArchive nuget = ZipFile.Open(file, ZipArchiveMode.Read))
            {
                foreach (ZipArchiveEntry entry in nuget.Entries)
                {
                    if (entry.Name.Contains(".dll"))
                    {
                        string createPathSource = @"C:\Users\userName\source\repos\core2.1test\core2.1test\nuqkgs\"+ entry.Name;

                        using (BinaryReader reader = new BinaryReader(entry.Open()))
                        {
                            // Step 1
                            using (FileStream fsNew = new FileStream(createPathSource, FileMode.Create, FileAccess.Write))
                            {
                                fsNew.Write(reader.ReadBytes((int)entry.Length), 0, (int)entry.Length);
                            }

                            // Step 2
                            using (FileStream readStream = File.Open(createPathSource, FileMode.Open))
                            {
                                var assempbly = AssemblyLoadContext.Default.LoadFromStream(readStream);
                                components.Add(assempbly);
                            }
                        }
                    }
                }
            }
        }
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

        services.AddMvc()
          .ConfigureApplicationPartManager(apm =>
          {
              foreach (var c in components)
              {
                  var part = new AssemblyPart(c);
                  apm.ApplicationParts.Add(part);
              }
          });
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接