tech.guitarrapc.cóm

Technical updates

Azure Functions で Asssembly.Location が正しくかえって来ない問題の対処

Azure Functions が6日ほど前に更新されて1.0.10690になってから、以下のエラーが発生する場合があります。

Can't create a metadata reference to an assembly without location.
  at Microsoft.CodeAnalysis.MetadataReference.CreateFromAssemblyInternal(Assembly assembly, MetadataReferenceProperties properties, DocumentationProvider documentation)
  at Microsoft.CodeAnalysis.Scripting.ScriptOptions.CreateReferenceFromAssembly(Assembly assembly)
  at Microsoft.CodeAnalysis.Scripting.ParameterValidationHelpers.<>c__DisplayClass4_0`2.<SelectChecked>b__0(T item)
  at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
  at Microsoft.CodeAnalysis.Scripting.ParameterValidationHelpers.AddRangeChecked[T](ArrayBuilder`1 builder, IEnumerable`1 items, String parameterName)
  at Microsoft.CodeAnalysis.Scripting.ParameterValidationHelpers.ToImmutableArrayChecked[T](IEnumerable`1 items, String parameterName)
  at Microsoft.CodeAnalysis.Scripting.ScriptOptions.WithReferences(IEnumerable`1 references)
  at Microsoft.CodeAnalysis.Scripting.ScriptOptions.WithReferences(IEnumerable`1 references)
  at Submission#0.<EvaluateCSharpAsync>d__3.MoveNext() in D:\home\site\wwwroot\CSharpScripting.csx:line 47

今回はこの発生原因と対処についてです。

目次

発生原因

最新バージョン 1.0.10690 で入った以下のコミットが原因です。

github.com

ということで、残念ながら現在 Azure Functions をコンソールから最新バージョン (1.0~) にするとエラーの起こっているバージョンになります。

現在のバージョンの確認

現在問題が起こるのかは、1.0未満なら Azure Functions の画面から確認できます。

1.0 、あるいはもっと正確に知りたい場合 Kudu を使います。

github.com

batコマンドだとこうですね。

type d:\local\config\applicationhost.config | findstr virtual | findstr Functions

表示された結果にバージョンが埋まっています。この場合なら 1.0.10690 となります。

<virtualDirectory path="/" physicalPath="D:\Program Files (x86)\SiteExtensions\Functions\1.0.10690" />

PowerShell でやりたい場合はこんな感じでどうでしょうか。

gist.github.com

問題が出るコード

Assembly.Load が正しい値を返さないのが問題です。Issue がすでに立っており、解決待ちステータスです。*1

github.com

今回私がひっかかったのが、Roslyn を使ったコード評価で独自dll を参照に追加するときでした。typeof(EnumerableExtensions).Assembly, の部分で独自dll のアセンブリを返していますがここでCan't create a metadata reference....エラーが出ます。

private static readonly Assembly[] DefaultReferences =
{
    typeof(Enumerable).Assembly,
    typeof(List<string>).Assembly,
    typeof(System.Net.Http.HttpClient).Assembly,
    typeof(EnumerableExtensions).Assembly,
};

https://github.com/guitarrapc/AzureFunctionsIntroduction/blob/master/CSharpScripting.csx#L39

対処

2つのワークアラウンドが提示されています。

  1. Azure Functions のバージョンをひとつ前に固定する
  2. 独自dllをFunctionフォルダ\bin ではない場所に配置する

今回私は 2の独自dll のパスを変更しています。修正PRは次のものです。

github.com

ワークアラウンドを見てみましょう。

(非推奨) Azure Functions のバージョンをひとつ前に固定する。

私個人としては非推奨です。

  1. バージョン追従がマニュアルになる
  2. 通常のフローではないバージョン管理が必要になる
  3. バージョン固定時に既存のFunction からFunctionが全部消える

特に、Function が全部消えるのは痛恨の罠です。Function Url というか code が作り直しになるので、外部連携している場合 URL 張り直しです。*2

一見コード修正もいらず最高かと思いましたがちょっと苦しいですね。

(推奨) 独自dllをFunctionフォルダ\bin ではない場所に配置する。

私個人としては推奨です。

過去には独自dll は {Function名}\bin\独自dll.dll 固定だったのですがどうやら制約はなくなったようです。reference には残っているので修正してほしいですね。

If you need to reference a private assembly, you can upload the assembly file into a bin folder relative to your function and reference it by using the file name (e.g. #r "MyAssembly.dll"). For information on how to upload files to your function folder, see the following section on package management.

docs.microsoft.com

修正も参照先アセンブリ #r の変更のみなので非常に容易です。

github.com

修正後

PRマージ前の問題発生中はエラーが返っていました。

一方、ワークアラウンド2の対処で修正後は問題なくAssembly を読んでコード評価しています。よかったです。

まとめ

おそらく近日中に修正されると思うので心待ちにしましょう。

Azure は、AzureFunctions などのAppService チームの中の人がふつーに Twitter で補足、アドバイスをくださり 神がかっています。*3

というのは別にしても、熱意と対応の速さは素晴らしく、真摯になっている姿勢を心から尊敬するとともに見習いたいと思います。

*1:正しく直す前に修正する場合に備えて、Revert コミットも準備してくれています : https://github.com/Azure/azure-webjobs-sdk-script/pull/1074

*2:これは Azure Functions の設計上の難しポイントでもあります。API Gateayなどが必要なのはこういう問題の対処です

*3:神が降臨したとTwitter リプライのたびに拝んでいます