在运行时加载 NuGet 依赖项 [英] Load NuGet dependencies at runtime

查看:39
本文介绍了在运行时加载 NuGet 依赖项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  1. 接收 NuGet 包列表(元组列表(包名称"、包版本"、主类路径").
  2. 在本地目录中检索它们(参见代码示例 #1)
  3. 在运行时将它们加载到我的程序中
  4. 通过自省运行主类(参见代码示例 #2)

现在我正在努力完成第三步.我不知道如何在运行时加载我的包.

我的主要问题是:

  • 如何知道检索到的包存放在哪些文件夹中?
  • 如何将这些目录的内容加载到我的程序中?

代码示例 #1:

private static void getPackageByNameAndVersion(string packageID, string version){IPackageRepository 回购 =PackageRepositoryFactory.Default.CreateRepository("https://packages.nuget.org/api/v2");字符串路径 = "C:/tmp_repo";PackageManager packageManager = new PackageManager(repo, path);Console.WriteLine("在 dl pkg 之前");packageManager.InstallPackage(packageID, SemanticVersion.Parse(version));}

代码示例 #2:

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

解决方案

来杯咖啡:)

正在下载 nuget 包?

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

var repo = PackageRepositoryFactory.Default.CreateRepository("https://packages.nuget.org/api/v2");字符串路径 = "c:\temp";var packageManager = new PackageManager(repo, path);packageManager.PackageInstalled += PackageManager_PackageInstalled;var package = repo.FindPackage("packageName", SemanticVersion.Parse("1.0.0"));如果(包!= null){packageManager.InstallPackage(package, false, true);}

<块引用>

请注意,我在 PackageManager 类的 PackageInstalled 事件中插入了一个事件处理程序.

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

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

公共类 TypeProxy : MarshalByRefObject{公共类型 LoadFromAssembly(字符串 assemblyPath,字符串 typeName){尝试{var asm = Assembly.LoadFile(assemblyPath);返回 asm.GetType(typeName);}捕捉(异常){返回null;}}}

现在,如何将它们组合在一起?

复杂的部分来了:

private static void PackageManager_PackageInstalled(object sender,PackageOperationEventArgs e){var files = e.FileSystem.GetFiles(e.InstallPath, "*.dll", true);foreach(文件中的 var 文件){尝试{AppDomain 域 = AppDomain.CreateDomain("tmp");类型 typeProxyType = typeof(TypeProxy);var typeProxyInstance = (TypeProxy)domain.CreateInstanceAndUnwrap(typeProxyType.Assembly.FullName,typeProxyType.FullName);var type = typeProxyInstance.LoadFromAssembly(file, "<KnownTypeName>");对象实例 =domain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName);}捕捉(例外前){Console.WriteLine("未能加载 {0}", file);Console.WriteLine(ex.ToString());}}}

<块引用>

注意这个方法是下载nuget包后执行的事件处理程序

还有

<块引用>

请注意,您需要将 <KnownTypeName> 替换为来自程序集的预期类型名称(或者可能运行程序集中所有公共类型的发现)

<小时>

值得注意的是,我自己还没有执行过这段代码,也不能保证它可以开箱即用,可能还需要一些调整.但希望它是可以让您解决问题的概念.

I'm looking for a way to run code by executing the following steps:

  1. Receiving a list of NuGet packages (a list of tuples ("package name", "package version", "path to main class").
  2. Retrieving them in a local directory (cf code sample #1)
  3. Loading them in my program at run-time
  4. Running the main classes by introspection (cf code sample #2)

By now I am struggling with the third step. I can't find out how to load my package at run-time.

My main question are:

  • How can I find out in which folders were stored the retrieved packages?
  • How can I load the content of those directories into my program?

Code Sample #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));

}

Code sample #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[] { });
}

解决方案

Grab a cup of coffee :)

Downloading the nuget package?

Nuget.Core (nuget package) is a good choice, and here is a snippet of code that I have that should be able to download a nuget package by id and version

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.

How do we load an assembly in an isolated app domain?

Since reflection API does not provide a way to load an assembly in a specific domain, We will create a proxy class that act as a loader in our isolated domain:

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; }
    }
}

And now, is how to put it all together?

Here comes the complex part:

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

Also

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)


Worth noting that I haven't executed this code myself and cannot guarantee that it will work out of the box, and still might need some tweaking. but Hopefully it is the concept that allows you to solve the problem.

这篇关于在运行时加载 NuGet 依赖项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆