Azure Functions では、関数の出力するデータをBlob や Queue に投げる処理を簡単にプログラムで書くことができます。
実装方法として、
があります。
今回は、Binder を使った命令型のバインディングの話です。
前置き - declarative binding
今回はこの話ではないですが、declarative binding を使うのが多いというか一般的?なので、さらっと触れておきます。
以下の感じで簡単に実装できます。
source-queue
キューにメッセージが入ると、Function App が起動- メソッドの引数として定義されている
outputQueueMessage
にセットした値がdestination-queue
キューにその値が出力される
6行目の関数の引数、 QueueAttribute
と out
がついている 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行目で、Binder
の BindAsync
メソッドで、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 の API が SQL、つまり 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