Blazor WebAssemblyアプリのコンテンツ読み込みから未使用の.dllを削除する方法


背景

Blazor WebAssembly アプリプロジェクトからクラスライブラリプロジェクトが参照されるシナリオを想像してください。

このシナリオでは、クラスライブラリから公開されるすべての型は、何らかの理由でリリースビルドの Blazor アプリで使用されることはありません。
(C#コンパイラの機能の一つである条件付きコンパイルで制御されているかもしれません)。

この場合、"Release" 設定で公開した Blazor アプリでは、"IL Linker" のトリミング機能によって、クラスライブラリ .dll ファイルがロードされないことが期待されます。

しかし、予想に反して、クラスライブラリ .dll ファイルは、どこにも使用されていないにもかかわらず、ブラウザに読み込まれます。😱

解決策

未使用のクラスライブラリ .dll ファイルをロードしないための解決策は、アセンブリレベルとしてクラスライブラリコードに AssemblyMetadata("IsTrimmable", "True") 属性を追加することです。

// このコードは、クラスライブラリの.csファイルのどこかに追加する必要があります。
[assembly: System.Reflection.AssemblyMetadata("IsTrimmable", "True")]

そうすれば、クラスライブラリがどこにも使われていない場合、ブラウザはクラスライブラリ .dll ファイルを読み込むことはありません。🎉

.NET 5 の場合

残念ながら、The AssemblyMetadata("IsTrimmable", "True") 属性は .NET 5 プラットフォーム上では、何の効果もありません

このシナリオに対する .NET 5 プラットフォームでの解決策は、以下のように Blazor WebAssembly アプリのプロジェクトファイル内に MSBuild スクリプトのいくつかを追加することです。

<!-- これは Blazor WebAssembly アプリの .csproj ファイルであり、クラスライブラリではありません。  -->
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
  ...
  <Target Name="_ConfigureAssemblyLevelTrimming" BeforeTargets="PrepareForILLink">
    <ItemGroup>
      <ManagedAssemblyToLink Condition="'%(Filename)' == 'SampleLib'">
        <IsTrimmable>true</IsTrimmable>
      </ManagedAssemblyToLink>
    </ItemGroup>
  </Target>
  ...

クラスライブラリを NuGet パッケージとして提供する場合、上記のようなMSBuild スクリプトも NuGet パッケージファイルに含めて、そのパッケージを参照するプロジェクトに自動的にインポートするように設定する必要があります。

このことは、.NET 6 以降のプラットフォームと比べ簡単ではありません。しかしながら、.NET 5 プラットフォームではこれ以外の方法はありません。

なお、.NET 5のサポート終了は2022年5月8日であることを忘れないでください。

公式ドキュメント

詳しくは、以下のマイクロソフト社の公式ドキュメントサイトをご覧ください。

📄 "追加のアセンブリのトリミング | Microsoft Docs"

公式ドキュメントでは、<TrimmableAssembly/>という MSBuild アイテムについても説明されています。
しかし、この記事では、<TrimmableAssembly/> MSBuild アイテムはあまり重要でないと考えているので、言及していません。