Azure Functionsの.NET Core3.1から.NET5への移行

はじめに

.NET5への移行概要

  • Azure Functionsの実行方法(モデル)が.NET isolated processに変更されました。
    • 以前のAzure Functionsでは、Azure Functionsランタイムとアプリを同一プロセスとして実行するイン・プロセス・モデルが採用されていました。このモデルでは、ランタイム(SDK)が提供する豊富な機能をアプリから無駄なく使用できます。一方で、アプリとランタイムで同じ.NET環境を使用する必要があるので、アプリとランタイムで使用するライブラリの競合、アプリのプロセスを自由にカスタマイズできない、等の問題(制約)が発生します。Azure Functions開発チームでは、新しい.NETバージョンに対応するのがいつも大変のようです。
    • そのため、.NET5からはランタイムとアプリを別プロセスとして実行するアウト・オブ・プロセス・モデル(.NETの用語としては.NET isolated process)が採用されました。
      (.NET5は長期サポートではなく、この挑戦が成功しなくても影響が少ないと判断したようです。)
    • .NET5以降のロードマップが公開されています。
      将来的にはアウト・オブ・プロセス・モデルに統一していくようです。.NET6ではイン・プロセスモデル/アウト・オブ・プロセスモデルのどちらも選択できますが、将来性を考えるならアウト・オブ・プロセス・モデルの使用をお薦めします。
      Future of .NET on Azure Functions ※マイクロソフト資料からの引用
    • その他詳細はこちらをご覧ください。
      TECHCOMMUNITY.MICROSOFT.COM

      Azure Functions now supports .NET 5. Learn about the new is…

  • .NET Core 3.1から.NET5に移行する手順の概要を次に示します。
    前述の実行モデルの変更に伴う改修が主となり、プロジェクトの形式変更、使用パッケージの.NET isolated process版への置き換えが必要になります。
    なお、HTTP以外のService BusやBlobトリガーの場合は、移行前後での改修は不要のようです。

    No.概要説明
    1プロジェクト
    定義の変更
    使用するフレームワークを.NET5、出力の種類をコンソールアプリケーション(Exe)に変更にします。
    2パッケージの変更Azure Functionsランタイムやトリガー用のパッケージを.NET isolated process用のパッケージ(Microsoft.Azure.Functions.Worker.*)に置き換えます。
    3起動方法の変更ASP.NET Coreアプリ等のようにホストビルダを使用してプロセスを初期化・実行します。(既存プロジェクトでスタートアップクラスを実装している場合は、DIサービス登録等の処理をこちらに移植する必要があります。)
    4メソッド定義の変更実行対象のメソッドに付与していたFunctionName属性をFunction属性に変更します。メソッド引数にILoggerを指定している場合は、FunctionContextから取得するよう変更します。
    5HTTPトリガー
    使用時の変更
    HTTPトリガーを使用する場合、
    引数・戻り値の型をHttpRequestData, HttpResponseDataに変更します。
    6ローカル実行用の
    ホスト定義の変更
    local.settings.jsonのワーカーランタイム(FUNCTIONS_WORKER_RUNTIME)を.NET isolated process(“dotnet-isolated”)に変更します。

.NET5への移行詳細

プロジェクト定義の変更

  • プロジェクトのプロパティを開きます。
    「対象のフレームワーク」を「.NET 5.0」、「出力の種類」を「クラスライブラリ」から「コンソールアプリケーション」に変更します。
  • プロジェクトファイル(.csproj)を直接編集する場合、次のようにTargetFramework/OutputType要素を編集します。

パッケージの変更

  • 既存のイン・プロセス・モデル用のパッケージを、アウト・オブ・プロセス・モデル用のものに置き換える必要があります。
    種類イン・プロセス・モデルアウト・オブ・プロセス・モデル
    ランタイムMicrosoft.NET.Sdk.FunctionsMicrosoft.Azure.Functions.Worker
    Microsoft.Azure.Functions.Worker.Sdk
    トリガーMicrosoft.Azure.WebJobs.Extensions.*Microsoft.Azure.Functions.Worker.Extensions.*
  • NuGetパッケージマネージャを起動してパッケージを置き換えます。
    NuGetパッケージマネージャの起動方法は、[ツール]-[NuGetパッケージマネージャー]-[ソリューションのNuGetパッケージの管理]、またはプロジェクトの[依存関係]-[パッケージ]を右クリックして[NuGetパッケージの管理]を選択します。
  • プロジェクトファイル(.csproj)を直接編集する方法もありますが、使用パッケージの最新安定バージョンが分からないので、前述のNuGetパッケージマネージャを使用する方法をお薦めします。
    (次の例ではHTTPトリガーを使用しています。)

起動方法の変更

  • イン・プロセス・モデルの場合、Azure Functionsプロセスの起動をランタイムが行うため、プロセス初期化処理は不要でした。プロセス初期化時に必要となるDIサービスの登録は、ランタイムがスタートアップクラスを実行することで実現します。
    アウト・オブ・プロセス・モデルの場合、ホストビルダ(IHostBuilder)を使用してアプリ自身でプロセスの初期化やDIサービス登録処理の呼び出しを実装する必要があります。
  • アプリの実行開始場所(エントリポイント)となるメソッドMain()を定義し、ホストビルダでConfigureFunctionsWorkerDefaults()を実行します。
    構成情報を追加する場合はConfigureAppConfiguration()、依存関係を注入(DI)する場合はConfigureServices()を使用します。

メソッド定義の変更

  • 関数のメソッドに付与されたFunctionName属性をFunction属性に変更します。
    なお、FunctionName属性の定義(FunctionNameAttribute)は、Microsoft.Azure.Functions.Worker.Extensions.Abstractionsパッケージにあります。HTTPやServiceBusトリガーを使用すると、その依存関係として自動的に参照が追加されます。
  • メソッドの引数でILoggerを引き渡している場合、FunctionContext経由で取得するよう変更します。

HTTPトリガー使用時の変更

  • メソッドの引数型HttpRequestをHttpRequestData、戻り値型IActionResultをHttpResponseDataに変更します。

ローカル実行用のホスト定義の変更

  • local.settings.jsonのFUNCTIONS_WORKER_RUNTIMEを、アウト・オブ・プロセス・モデルである”dotnet-isolated”に変更します。

トラブルシューティング

ホストが開始していない

  • 事象
    ローカルで実行時に次のエラー・例外が発生して中断する。

    • Azure Functions Core Toolsのコンソールでは次のエラーが表示される。
      Microsoft.Azure.WebJobs.Script: Did not find functions with language [dotnet].
    • アプリのコンソールでは、Microsoft.Azure.WebJobs.Hostで次の例外が発生する。
      System.InvalidOperationException("The host has not yet started.")
  • 原因
    local.settings.jsonのFUNCTIONS_WORKER_RUNTIMEが”dotnet-isolated”以外になっていることが原因。(当該値に変更する必要がある。)
  • 原因
    • プロジェクトをビルドする際、ランタイムと共有するアセンブリ(パッケージ)は最適化のために単一バージョンのみ保持(それ以外は削除)されます。同一パッケージで異なるバージョンのパッケージを使用している場合、ビルド時にいずれかのバージョンのものが削除されるため、この例外が発生します。
    • Microsoft.NET.Sdk.Functions 3.0.12より前では、プロジェクトのプロパティで”_FunctionsSkipCleanOutput”を宣言することで、この動作を抑制できます。
    • Microsoft.NET.Sdk.Functions 3.0.12以降では、保持対象とするパッケージをFunctionsPreservedDependencies要素で指定できます。

      Azure Functions Tools for Visual Studio 2022 を使用して、Azure Fun…

    • その他詳細はこちらが参考になると思います。

gRPC公開ポイントの不正

  • 事象
    Azure Functionsアプリを起動すると、次の例外が発生して実行が中断される。

    Unhandled exception. System.InvalidOperationException: The gRPC channel URI 'http://:0' could not be parsed.
  • 原因
    • gRPCの公開ポイントは構成情報(IConfiguration)から取得します。何らかの理由で公開ポイントを取得できない場合、この事象が発生します。
    • 既定ではAzure Functionsホストビルダ実行時のConfigureFunctionsWorkerDefaults()で、構成情報が初期化されます。作成された構成情報に対して、意図しない操作を行い、構成情報のクリアや上書きをしている可能性があります。
    • 構成情報(IConfiguration)構成情報ビルダ(IConfigurationBuilder)に対する操作を追跡することで、原因個所を特定できると思います。
    • なお、次のように構成情報ビルダのソースをクリアすると同事象を再現できます。