BEACHSIDE BLOG

MicrosoftとかC#を好むレンジャーの個人的メモ

Azure Functions の バインディング - Binder 編

Azure Functions では、関数の出力するデータをBlob や Queue に投げる処理を簡単にプログラムで書くことができます。
実装方法として、

があります。

今回は、Binder を使った命令型のバインディングの話です。

前置き - declarative binding

今回はこの話ではないですが、declarative binding を使うのが多いというか一般的?なので、さらっと触れておきます。

以下の感じで簡単に実装できます。

  • source-queue キューにメッセージが入ると、Function App が起動
  • メソッドの引数として定義されている outputQueueMessage にセットした値が destination-queue キューにその値が出力される

6行目の関数の引数、 QueueAttributeout がついている outputQueueMessage に対し、11行目で値をセットしています。これだけでいい感じにバインドしてくれるやつです。

(説明雑すぎでしょうか...)


ここからが本題で、
命令型のバインディングimperative binding )のメモです。

環境

細かい情報は書きませんが主要な環境情報として、

  • Visual Studio 2017 で Azure Functions でプロジェクトを作成
    つまり、C# スクリプト(.csx)ではなく、C#での実装。
  • Nuget Package の Microsoft.NET.Sdk.Functions : v1.0.8
  • Azure 上の Function App は、ランタイム バージョン: 2.0.11415.0 (beta)

で行っています。

また、この後出てくるサンプルコードでは、Person クラスって雑なモデルをやり取りすることを前提とします。

Id プロパティを string にしてるのは、諸事情で意図的にしています。

Binder

imperative binding では、関数の引数に Binder を定義して使います。DIしてくれるので、インスタンスのあれこれをあまり気にする必要がありません。

Queue へのバインディング

サンプルコードは、2つの関数がありますが、内容はほぼ一緒で以下です。

  • トリガー:Queue トリガー
  • 出力:Queue にメッセージを投げる

16行目にある1つ目のメソッド Run のざっくり解説です。
20行目で、QueueAttributeインスタンス化しています。引数にはQueue名を指定しています。接続文字列を指定していないので、デフォルト値を取ってきます(そこらへんは前回参照)。

22-23行目で、BinderBindAsync メソッドで、QueueAttribute 渡してあげます。あとはコードに書いてる通りですね。これだけでキューに送る処理完了。シンプル!

27行目、2爪のメソッド RunQueueBind2 は、 同様にキュートリガーですが、異なる点は、出力先が、トリガーのストレージとは別の Storage のキューにメッセージを投げています。これは、31-34行目で attribute の配列をインスタンス化し、接続文字列を指定した StorageAccountAttribute をセットすることで、容易に実現しています。

こんな感じで複数のバインドも簡易できたりしますので、ケースバイケースで使えそうです。


Blob へのバインディング

こんなサンプルです。

  • トリガー:Queue トリガー
  • 出力:Blob にテキストを保存

ちょっとしたメッセージをblobにtxtに保存するにはこれだけでOKです。もちろん、先ほど同様にAttribute を配列にして StorageAccountAttribute も渡すこともできます。


CosmosDB(API: SQL) バインドの例

GitHub を見る限り、SDK が絶賛対応中なので、ブログ書き途中で、色んな意味でこの時期にブログに書く意味ないなぁと感じています。

2018年2月時点の情報です。

気になるポイントがいくつもありましたが、そのうちの3つをあげておきます。

1つめ

今回バインディングする CosmosoDB の APISQL、つまり DocumentDB では、id というキーの名称は string なので、よくありそうな int 型の id ってプロパティを直接渡すと死にます。
ガチな時は、状況に合わせて CosmosDB 格納用に Model のクラス作るとか、Jsonに変えたり戻りしたりする拡張メソッド用意するとかどうにでもできますね。

2つめ

2018年2月時点だと、
Nuget パッケージ の、Microsoft.Azure.WebJobs.Extensions.DocumentDB (v1.1.0)を利用すると .NET Core 環境では Exception 吐き、同じコードを .NET Framework 環境で行うと実行できます。

Microsoft.Azure.WebJobs.Extensions.CosmosDB(現時点での最新は3.0.0-beta6)は、.NET Framework環境だと依存関係でアウトです。 .NET Core 環境でも上記同様の Exception 吐いたので...時間都合でみるのやめました。
今回は、.NET Framework 環境で進めます。

3つめ

接続文字列とかの情報は、ローカルデバッグ用に local.settings.json で定義するってことを前回ざっくり書きましたが、ConnectionStrings セクションからのデータを読み取れないです。 下の方にCosmosDBバインディングのサンプルコードを張っていますが、30行目の ConnectionStringSetting = "MyCosmos" を ConnectionStringSetting = "ConnectionStrings:MyCosmos" と書いてもダメでした。
Values セクションに定義してあげる必要があります。

SDKの実装ぱっとみたとろこ、ConnectionStringsでも値を取得できそうにみえたけど動かなかったので、みるとこおかしかったか...とにかく最近寝る時間削るほどドタバタしているので、気になるけど追うのはやめときます。手が空いて実務で使うときにまた見よう。


ここからは、
前提が変わり、.NET Framework 環境(Function App のV1)で Function App のプロジェクトを作っての話です。
あと、Nuget Package で、Microsoft.Azure.WebJobs.Extensions.DocumentDB をインストールしています。

サンプルの内容は、以下。

  • トリガー:Queue トリガー
  • 出力:CosmosDB にデータを保存する

15行目の Run メソッドで引数の Queue トリガーで受け取ったメッセージを CosmosDB に送るサンプルです。

ということで、21行目で DocumentDBAttributeインスタンス化しています。

Queue に投げたメッセージは、例えば以下のようなJSONです。

{"id":"100-1","name":"yokohama"}

便利なモデルバインディングの機能はあるので、上記JSON を送信して、引数の型を Person 型にしてあげればOKです。 JObject 型でモデルバインディングして値をいじるってケースとかもありますね。


参考

Azure Functions C# developer reference (Azure Functions C# 開発者向けリファレンス) | Microsoft Docs