考虑一个引用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
行,那么将不加载程序集,因此GetReferencedAssemblies
或GetAssemblies
都不可用
.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>()
),但是它使用反射来实现-例如proto工厂找到一个实现IAuditEvent
的类,但它也是Protobuf生成的类。如果没有首先加载程序集,它将无法工作...
答案 0 :(得分:1)
这实际上取决于战略。如果您发现自己需要中介来反映和提供类型,则是考虑IoC容器的好时机。
在这里,您有几种选择:
答案 1 :(得分:1)
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)”
尽管这还远非理想,希望您能提出更好的建议。