【问题标题】:Load NuGet dependencies at runtime在运行时加载 NuGet 依赖项
【发布时间】:2015-10-29 19:24:30
【问题描述】:

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

  1. 接收 NuGet 包列表(元组列表(“包名称”、“包版本”、“主类路径”)。
  2. 在本地目录中检索它们(参见代码示例 #1)
  3. 在运行时将它们加载到我的程序中
  4. 通过自省运行主类(参见代码示例 #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[] { });
}

【问题讨论】:

    标签: c# .net runtime nuget add-in


    【解决方案1】:

    喝杯咖啡:)

    正在下载 nuget 包?

    Nuget.Core(nuget 包)是一个不错的选择,这是我拥有的一个 sn-p 代码,应该可以通过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);
    }
    

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

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

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

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

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

    还有

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


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

    【讨论】:

    • 您的示例的一个问题是 PackageManager_PackageInstalled 仅在第一次在 c:\\temp 中安装所询问的包时才调用。如果它在之前的代码执行中已经存在,则不会调用 PackageManager_PackageInstalled。
    【解决方案2】:

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

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

    【讨论】:

    • 我理解您的担忧,但我正在编写的软件的主要目标是在运行时加载软件组件。所以加载的代码将是第三方的,我在构建时不知道。但是无论如何感谢这个明智的建议:)
    猜你喜欢
    • 2020-04-04
    • 1970-01-01
    • 1970-01-01
    • 2018-06-20
    • 2019-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多