簡體   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