【问题标题】:Load assembly in Startup.cs .net core 2.1在 Startup.cs .net core 2.1 中加载程序集
【发布时间】:2019-01-30 05:58:49
【问题描述】:

我在名为 nuqkgs 的文件夹中有 nugget 包,在项目启动时,我想将这些包(有 dll)加载到项目中以在运行时使用。

我使用下面的代码来加载它们,当我调试时我可以看到信息并且找到并打开了 dll,但是当它们应该被使用时,我得到了找不到 dll 的错误,我可以看到解决方案尝试在 bin 文件夹中查找它们(它们位于 solution/nuqkgs/)

我不想在任何文件中注册包,我只是希望能够将 nugget 包放入 nuqkgs 文件夹并自动注册

有任何想法或任何人在核心 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);
 }

【问题讨论】:

  • 这只是一个非常糟糕的计划。我知道您要做什么,但是动态引用只会使您的代码变得愚蠢复杂。一方面,您必须始终保持动态,这意味着使用这些动态加载的程序集的所有代码也必须通过反射调用。您的代码将只是一堆字符串引用,这将非常脆弱,并且您的所有错误都将是运行时错误而不是编译时错误,就像您真正想要的那样。
  • 它将用于插件架构的解决方案,因此在放入文件夹之前,所有错误都将在单个块中编译时被捕获
  • 抱歉,我不明白金块与此有什么关系?您打算实时添加 dll 还是每次启动只添加一次?
  • 正如您在代码中看到的,文件夹中有一个块,我提取了该块并希望在每个包中注册和使用 dll。如果我们将另一个 nugget 包添加到文件夹中,我们将重新启动应用程序,它应该会被注册
  • 不。根据定义,您在运行时加载程序集,因此绝对无法在编译时捕获错误。在编译期间,应用程序不会知道任何此代码或引用存在。

标签: c# .net asp.net-core-2.1


【解决方案1】:

docs for AssemblyLoadContext 中所述,Assembly.Load(byte[]) 在新的未命名加载上下文中加载程序集,而AssemblyLoadContext(默认的除外)目前无法解析依赖关系。这可能就是您的零件无法正常工作的原因。尝试使用AssemblyLoadContext.Default.LoadFromStream 而不是Assembly.Load(byte[])

【讨论】:

    【解决方案2】:

    我得到它的工作,我现在使用它的方式:

    1. 打开 nuget foreach DLL,我将 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);
                  }
              });
        }
    

    【讨论】:

      猜你喜欢
      • 2017-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-26
      • 1970-01-01
      相关资源
      最近更新 更多