繁体   English   中英

如何动态加载项目引用但代码未引用的程序集

[英]How can I dynamically load assemblies referenced by project, but not referenced in code

考虑一个引用NuGet包的.NET Core应用程序。

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.2</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="MyPackage" Version="1.0.0" />
  </ItemGroup>

</Project>

如果我的代码引用MyPackage的类型,则将加载MyPackage程序集。 如果我打印出所有引用或加载的程序集,则它将出现。

static void Main(string[] args)
{
    // Because I have a reference to a type in MyPackage, the assembly 
    // is loaded and will be printed out by both foreach statements below.
    var throwaway = typeof(MyPackage.Cars);
    foreach (var an in Assembly.GetEntryAssembly().GetReferencedAssemblies())
    {
        WriteLine(an.Name);
    }

    foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
    {
        WriteLine(assembly.FullName);
    }
}

但是,如果我摆脱了那条throwaway线,那么就不会加载程序集,因此GetReferencedAssembliesGetAssemblies都不可用。

.NET Framework也存在相同的问题,通常的解决方法是读取执行文件夹中的所有程序集并手动加载它们,例如:

Directory
    .GetFiles(executingFolder, "*.dll", SearchOption.TopDirectoryOnly)
    .Select(AssemblyLoadContext.Default.LoadFromAssemblyPath));

但是,.NET Core将从其他位置加载程序集(例如NuGet缓存-到目前为止,我还没有找到有关新绑定过程的全面描述),因此上述方法将行不通。

因此,我的问题是:如何动态加载csproj文件引用的所有DLL(作为NuGet PackageReferences)。 我的用例相当神秘,因此我认为没有其他机制可以使用。

背景

好的,所以有人要问我的用例是什么,就在这里。

我们有一组定义消息的接口(IAuditEvent,IValidationEvent等)。 我们还为不同的序列化格式(Protobuf,XML,JSON等)提供了这些接口的各种实现。 其中每个都是单独的NuGet程序包(MyMessages.Proto,MyMessages.Xml)。

我们有一个工厂将创建适当的实现( factory.Create<IAuditEvent>() ),但是它使用反射来完成此操作-例如,原型工厂找到实现IAuditEvent的类,但也是Protobuf生成的类。 如果未首先加载程序集,则无法使用...

这一点实际上取决于策略。 如果您发现自己需要中介来反映和提供类型,则是考虑IoC容器的好时机。

在这里,您有几种选择:

Assembly.GetReferencedAssemblies不会返回您的程序集,因为它实际上没有被引用。 如果您看一下exe文件的清单,您将找不到引用,就像编译器对其进行了优化一样。

AppDomain.GetAssemblies返回实际加载的程序集,请考虑:

static void Main(string[] args)
{
    foreach (var an in Assembly.GetEntryAssembly().GetReferencedAssemblies())
    {
        WriteLine(an.Name);
    }

    foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
    {
        WriteLine(assembly.FullName);
    }

    LoadType();
}

static void LoadType()
{
    typeof(MyPackage.Cars);
}

在这种情况下,GetReferencedAssemblies调用的结果始终是相同的,但是GetAssemblies结果取决于您在调用GetAssemblies之前或之后放置LoadType的位置。

在构建服务器上,您不需要构建解决方案,而是发布解决方案,因此扫描程序集只是开发时间问题。 您可以在构建后事件中添加以下内容,也可以在项目中的dev目标中添加以下内容,并使用Daniel建议的方法之一:

dotnet发布“ $(ProjectPath)” --no-build -o“ $(TargetDir)”

但是,这远非理想,希望您能提出更好的建议。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM