xin9le.net

Microsoft の製品/技術が大好きな Microsoft MVP な管理人の技術ブログです。

_FunctionsSkipCleanOutput を利用しないで Azure Functions プロジェクトのビルド時 DLL 自動削除から DLL を保護する

タイトルが長過ぎてなんのこっちゃワカランと思います。僕も良いタイトルが浮かびません...(

今回は下記の Issue の内容と公式回答についてザックリ解説します。僕の理解が正確かは分からないので、Issue も読んでもらえると助かりますw

Issue の内容

  • System.Interactive.Async v4.1.1 を NuGet 参照してる Azure Functions プロジェクトがある
    • この NuGet パッケージは C# 8.0 以降で言語サポートされた IAsyncEnumerable<T> を利用するときに高頻度で利用する
  • Azure Functions v3 にデプロイしたら「dll がないぜ!」って例外飛んで動かない!
  • どうやら RemoveRuntimeDependencies のせいで System.Interactive.Async.dll が削除されちゃってるっぽい
  • Microsoft.NET.Sdk.Functions を更新したのが問題ぽい
    • v3.0.3 までは動いてた

背景

Azure Functions は起動高速化などを目的として Functions Host が利用している dll と重複している dll をビルド時に削除するようになっています。これは .csproj ビルド時に RemoveRuntimeDependencies タスクが動くことで実現されていて、既定で有効です。削除対象となる dll は runtimeassemblies.json にリストされているのですが、ここに System.Interactive.Async.dll が入っています。Microsoft.NET.Sdk.Functions v3.0.4 以降で System.Interactive.Async.dll が追加されたようで、「Functions SDK を更新 (v3.0.4+) したら突然動かなくなった!」という感じです。実際僕も業務で同じ問題にブチ当たってしばらくハマりました。

ここで問題だったのが RemoveRuntimeDependencies で削除する際に dll のバージョンを見てくれていなかったことです *1。Azure Functions v3 Host は System.Interactive.Async.dll v3.x.x を参照しているのですが、プロジェクト側で NuGet 参照して利用している v4.x.x を問答無用で削除してしまうことで問題が発生していました。C# 8.0 以降を利用するときに大変相性が悪い事案でツラぽよでした。

これまでの回避策

アセンブリ自動削除が行われなければ問題が起こらないので、RemoveRuntimeDependencies タスクを Opt-out します。_FunctionsSkipCleanOutput = true を .csproj に記述すれば OK です。

<PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <AzureFunctionsVersion>v3</AzureFunctionsVersion>

    <!-- ↓↓ コレを追加 ↓↓ -->
    <_FunctionsSkipCleanOutput>true</_FunctionsSkipCleanOutput>
</PropertyGroup>

という workaround を知っていたのでコメントしておきました。それが 2020 年 7 月の話です。

新しい回避策

それから半年以上経過した 2021 年 3 月。つい最近です。オフィシャルな回答として以下が提示されました。簡単に言うと除外する dll を除外リストに入れられるようになったという感じです。

  1. Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator 1.2.1 以降を参照
  2. <FunctionsPreservedDependencies Include="xxx.dll" /> で除外リストに追加
<ItemGroup>
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.11" />

    <!-- ↓↓ コレを追加 ↓↓ -->
    <PackageReference Include="Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator" Version="1.2.1" />
    <FunctionsPreservedDependencies Include="System.Interactive.Async.dll" />
</ItemGroup>

削除されると困る dll を適宜羅列することで、RemoveRuntimeDependencies による出力アセンブリの最適化の恩恵も得られる形になりました。大変ハッピー!

*1:今はバージョンも見て削除しているような気がしなくないですが、まだ未確認なのであまり信じないでください