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で入った以下のコミットが原因です。
https://github.com/fabiocav/azure-webjobs-sdk-script/commit/94d066038eddfc5e6360b28f4ef267956992446e
ということで、残念ながら現在Azure Functionsをコンソールから最新バージョン (1.0~) にするとエラーの起こっているバージョンになります。
現在のバージョンの確認
現在問題が起こるのかは、1.0未満ならAzure Functionsの画面から確認できます。

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


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でやりたい場合はこんな感じでどうでしょうか。
https://gist.github.com/guitarrapc/f4c3650cb9785c49fd9704c21707a806

問題が出るコード
Assembly.Loadが正しい値を返さないのが問題です。Issueがすでに立っており、解決待ちステータスです。*1
https://github.com/Azure/azure-webjobs-sdk-script/issues/1073
今回ひっかかったのが、Roslynを使ったコード評価で独自dllを参照に追加するときでした。typeof(EnumerableExtensions).Assembly,の部分で独自dllのアセンブリを返していますがここでtypeof(EnumerableExtensions).Assembly,エラーが出ます。
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つのワークアラウンドが提示されています。
- Azure Functionsのバージョンをひとつ前に固定する
- 独自dllを
Functionフォルダ\binではない場所に配置する
今回私は2の独自dllのパスを変更しています。修正PRは次のものです。
https://github.com/guitarrapc/AzureFunctionsIntroduction/pull/3
ワークアラウンドを見てみましょう。
(非推奨) Azure Functions のバージョンをひとつ前に固定する。
私個人としては非推奨です。
- バージョン追従がマニュアルになる
- 通常のフローではないバージョン管理が必要になる
- バージョン固定時に既存の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.
https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-csharp
修正も参照先アセンブリ#rの変更のみなので非常に容易です。
https://github.com/guitarrapc/AzureFunctionsIntroduction/pull/3/files

修正後
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リプライのたびに拝んでいます