在运行时加载 NuGet 依赖项

Load NuGet dependencies at runtime

我正在寻找一种通过执行以下步骤来 运行 代码的方法:

  1. 正在接收 NuGet 包列表(元组列表 ("package name"、"package version"、"path to main class")。
  2. 在本地目录中检索它们(参见代码示例 #1)
  3. 在 运行-time
  4. 将它们加载到我的程序中
  5. 运行 主要 类 内省(参见代码示例 #2)

现在我正在为第三步而苦苦挣扎。我找不到如何在 运行 时间加载我的包裹。

我的主要问题是:

代码示例 #1:

private static void getPackageByNameAndVersion(string packageID, string version)
{
    IPackageRepository repo =
            PackageRepositoryFactory.Default
                  .CreateRepository("https://packages.nuget.org/api/v2");

   string path = "C:/tmp_repo";
   PackageManager packageManager = new PackageManager(repo, path);
   Console.WriteLine("before dl pkg");
   packageManager.InstallPackage(packageID, SemanticVersion.Parse(version));

}

代码示例 #2:

private static void loadByAssemblyNameAndTypeName(string assemblyName, string typeName)
{
   AppDomain isolationAppDomain = AppDomain.CreateDomain("tmp");
   object a = isolationAppDomain.CreateInstanceAndUnwrap(assemblyName, typeName);
   Type x = a.GetType();
   MethodInfo m = x.GetMethod("Main");
   m.Invoke(a, new object[] { });
}

喝杯咖啡:)

正在下载 nuget 包?

Nuget.Core(nuget 包)是一个不错的选择,这里是我拥有的一段代码,应该能够通过 idversion 下载 nuget 包

var repo = PackageRepositoryFactory.Default
                .CreateRepository("https://packages.nuget.org/api/v2");

string path = "c:\temp";
var packageManager = new PackageManager(repo, path);
packageManager.PackageInstalled += PackageManager_PackageInstalled;

var package = repo.FindPackage("packageName", SemanticVersion.Parse("1.0.0"));
if (package != null)
{
    packageManager.InstallPackage(package, false, true);
}

Notice that I plugged an event handler to the PackageInstalled event of the PackageManager class.

我们如何在独立的应用程序域中加载程序集?

由于反射 API 不提供在特定域中加载程序集的方法,我们将创建一个代理 class 作为我们隔离域中的加载程序:

public class TypeProxy : MarshalByRefObject
{
    public Type LoadFromAssembly(string assemblyPath, string typeName)
    {
        try
        {
            var asm = Assembly.LoadFile(assemblyPath);
            return asm.GetType(typeName);
        }
        catch (Exception) { return null; }
    }
}

现在,是如何把它们放在一起的?

复杂的部分来了:

private static void PackageManager_PackageInstalled(object sender, 
                                                    PackageOperationEventArgs e)
{
    var files = e.FileSystem.GetFiles(e.InstallPath, "*.dll", true);
    foreach (var file in files)
    {
        try
        {
            AppDomain domain = AppDomain.CreateDomain("tmp");
            Type typeProxyType = typeof(TypeProxy);
            var typeProxyInstance = (TypeProxy)domain.CreateInstanceAndUnwrap(
                    typeProxyType.Assembly.FullName,
                    typeProxyType.FullName);

            var type = typeProxyInstance.LoadFromAssembly(file, "<KnownTypeName>");
            object instance = 
                domain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName);
        }
        catch (Exception ex)
        {
            Console.WriteLine("failed to load {0}", file);
            Console.WriteLine(ex.ToString());
        }

    }
}

Notice that this method is the event handler that gets executed after downloading the nuget package

还有

Note that you will need to replace <KnownTypeName> with the expected type name coming from the assembly (or maybe run a discovery of all public types in the assembly)


值得注意的是,我自己没有执行过这段代码,因此不能保证它可以开箱即用,而且可能仍需要一些调整。但希望这个概念能让你解决问题。

不要那样做!您可能正试图在客户的计算机上加载 NuGet 内容以节省一些 space 软件分发费用。不是吗?

通常推荐的方法是下载 NuGet 内容作为自动构建的第二步(在下载源代码之后),使用您下载的 NuGet 内容构建软件和运行 自动化测试.然后分发包含您测试过的 NuGet 内容的构建作为复杂的整体单元。