Dictionary to Objectのマッパーを使う - Slapper.AutoMapper

本日、会社でDictionaryオブジェクトからObjectへのオートマッパーを行う方法知りませんかー?と聞かれまして・・・
決め打ちの固定プロパティへのマッピングであれば、AutoMapperのMapFromで出来るかなぁ・・・と思ったのですが・・・
要件としてはプロパティ名を決め打ちしない動的マッピングなのです。

ということでググったら、StackOverflow経由で Slapper.Automapper なるものを見つけましたので、ここにメモしておきます。
といっても結構前からgithubに上げられていたライブラリになります。

Slapper.AutoMapper

これです!

github.com

普通にVSからNugetで取得することができます。

Slapper!!!なんかかっこいいですね。そのままの動きをします。

何をするもの?

まあ、つまり「Dictionaryオブジェクトから任意のオブジェクトへのマッパー」を可能にします。

以下の リスト1 のオブジェクトを、一発で リスト2 のオブジェクトにマッピングします。

// リスト1
var src = new Dictionary<string, object>();
src.Add("IntProp1", 10);
src.Add("IntProp2", 20);
src.Add("IntProp3", 30);
src.Add("IntProp4", 40);
src.Add("IntProp5", 50);
src.Add("StringProp1", "10");
src.Add("StringProp2", "20");
src.Add("StringProp3", "30");
src.Add("StringProp4", "40");
src.Add("StringProp5", "50");
// リスト2
public class TestClass
{
  public int IntProp1 { get; set; }
  public int IntProp2 { get; set; }
  public int IntProp3 { get; set; }
  public int IntProp4 { get; set; }
  public int IntProp5 { get; set; }

  public string StringProp1 { get; set; }
  public string StringProp2 { get; set; }
  public string StringProp3 { get; set; }
  public string StringProp4 { get; set; }
  public string StringProp5 { get; set; }
}

使い方

以下のリスト3が使い方のサンプルです。

// リスト3
namespace ConsoleApp1 {
  class Program {
    static void Main(string[] args) {
      // データソースを作成
      Dictionary<string, object> src = new Dictionary<string, object>();
      src.Add("IntProp1", 10);
      src.Add("IntProp2", 20);
      src.Add("IntProp3", 30);
      src.Add("IntProp4", 40);
      src.Add("IntProp5", 50);
      src.Add("IntProp6", 60);  // マップ先に存在しないプロパティは無視される
      src.Add("StringProp1", "10");
      src.Add("StringProp2", "20");
      src.Add("StringProp3", "30");
      src.Add("StringProp4", "40");
      src.Add("StringProp5", "50");
      
      
      // 一発でマッピング!!
      var desc = Slapper.AutoMapper.Map<TestClass>(src);
    }
  }
  
  // マップ先のオブジェクト
  public class TestClass
  {
      public int IntProp1 { get; set; }
      public int IntProp2 { get; set; }
      public int IntProp3 { get; set; }
      public int IntProp4 { get; set; }
      public int IntProp5 { get; set; }

      public string StringProp1 { get; set; }
      public string StringProp2 { get; set; }
      public string StringProp3 { get; set; }
      public string StringProp4 { get; set; }
      public string StringProp5 { get; set; }

      public string NothingText { get; set; } // ソースにないプロパティはnull(number系の型なら 0 )
  }
}

ちなみに AutoMapper と名が付きますが、いわゆる本家AutoMapperは全く内部的にも使っていません。
githubで公開されているので、ソースを見ればわかりますが、シンプルなReflectionによるMapper解決を行っています。

※最近ブログをさぼっていたのでウォーミングアップ的ブログ投稿でした。
でも、何気に要求的にはよくありそうな話なので、本投稿がGoogleで引っかかってどなたかのお役に立てれば^^です!

C#7.1のAsync Mainがお気に入り~Visual Studio 2017 Update 3(15.3)

Visual Studio 2017 Update3(15.3)が 2017/8/14 にリリースされました。

www.visualstudio.com

.NET Core 2.0サポートだったり、コンパイルベースのAzure Functionsサポートのような今までPreview版を利用しなければならなかった機能が正式版で使えるようになりました。

1. C# 7.1サポート

で、その中に「C# 7.1言語機能の追加」ってものもありました。

C# 7.1機能として以下のような機能が使えるようになりました。

  • async Main methods
  • pattern-matching with generics
  • “default” literals
  • inferred tuple names

2. async Main methodのサポート

個人的には「async Main methods」が何気にお気に入りです。

普段の開発作業においてサンプル実装を試すのに、コンソールアプリプロジェクトを利用することが結構あります。
この時、従来はMain()メソッドにasyncを付けることができなかったので、以下のようなことをする必要がありました。

↓↓↓こんなやり方や・・・

// リスト1

// C# 7.0までは・・・。
// Main()以外に非同期版メソッドを用意して呼び出し
static void Main(string[] args)
{
  MainAsync().GetAwaiter().GetResult();
}

private static async Task MainAsync()
{
  string html = await new HttpClient().GetStringAsync("http://www.yahoo.co.jp");
  Console.WriteLine( html );
}

↓↓↓こんなやり方など・・・

// リスト2

// C# 7.0までは・・・。
// 試したいメソッドに .Result をつける(実際の使い方と異なる形になる)
static void Main(string[] args)
{
  string html = await new HttpClient().GetStringAsync("http://www.yahoo.co.jp").Result;
  Console.WriteLine( html );
}

C# 7.1では以下のような実装が可能になりました。

// リスト3

// C# 7.1版
// Mainにasyncが付けられる!!
static async Task Main(string[] args)
{
  string html = await new HttpClient().GetStringAsync("http://www.yahoo.co.jp");
  Console.WriteLine( html );
}

Main()メソッドにasyncが付けられるようになったことで、直接的に実装を記述することができるようになりました。

3. 利用する C# のバージョン

利用する C# のバージョンはプロジェクトのプロパティで設定することができます。
デフォルトでは「最新のメジャーバージョン」が既定になっています。つまり VS2017 Update3(15.3) で作成したプロジェクトは、そのまま C# 7.1 が利用可能です。
プロジェクトで明示的に利用する C#バージョン を設定する方法は以下の通りです。

(1) プロジェクトプロパティの表示

ソリューションエクスプローラでプロジェクトをマウス右ボタンクリック。
表示されたメニューから「プロパティ」を選択します。

f:id:daigo-knowlbo:20170815151415p:plain

(2) C#バージョンの選択

表示されたプロパティ ペインから「ビルド」を選択し、「詳細設定」ボタンをクリックします。

f:id:daigo-knowlbo:20170815151454p:plain

表示された「ビルドの詳細設定」ウィンドウで、「言語バージョン」を選択します。

f:id:daigo-knowlbo:20170815151519p:plain

f:id:daigo-knowlbo:20170815151529p:plain

Azure FunctionsでCosmos DBを入力バインドする

以前「Azure FunctionsからCosmos DBに出力バインドする」という記事を書きましたので、それと対になる形で入力バインドについても簡単にまとめておこうと思います。

ryuichi111std.hatenablog.com

今回 実装することは以下の通りです。

  • HttpTriggerを持つAzure Functionsを作成
  • Cosmos DBドキュメントを入力バインドで受け取る
  • Function内の処理で、受け取ったCosmos DBドキュメントに変更を加える

1 開発環境

利用する環境は、以下の通りです。

2 前提条件

以下のような Cosmos DB アカウント を用意している前提とします。

f:id:daigo-knowlbo:20170814014414p:plain

  • APIモデルは「DocumentDB」
  • データベース名「CompanyDB」、コレクション名「EmployeeCollection」を作成済
  • ドキュメントが1件登録済み(id=“0000000001")
-- 登録済みドキュメント --
{
  "id": "0000000001",
  "firstname": "ryuichi",
  "lastname": "daigo",
  "_rid": "5T9QALZ5bQABAAAAAAAAAA==",
  "_self": "dbs/5T9QAA==/colls/5T9QALZ5bQA=/docs/5T9QALZ5bQABAAAAAAAAAA==/",
  "_etag": "\"0300aeae-0000-0000-0000-599081c20000\"",
  "_attachments": "attachments/",
  "_ts": 1502642619
}

3 実装

Visual Studio 2017 Preview(15.3)を起動します。

(1) プロジェクト作成

メニュー「ファイル → 新規作成 → プロジェクト」を選択します。

「新しいプロジェクト」ウィンドウが表示されます。
以下の入力を行います。

  • プロジェクトテンプレート:「Visual C# → Cloud → Azure Functions」
  • 名前:適当に・・・ここではデフォルトの FunctionApp1 にしました

f:id:daigo-knowlbo:20170814014959p:plain

設定用JSONのみの空っぽのソリューションが出来上がります。

f:id:daigo-knowlbo:20170814015222p:plain

(2) Functionsコードの追加

ソリューションエクスプローラで FunctionApp1 をマウス右ボタンクリック。
表示されたメニューから「追加 → 新しい項目」を選択します。

f:id:daigo-knowlbo:20170814015448p:plain

「新しい項目の追加」ウィンドウが表示されるので、「Azure Function」アイテムを追加します。
ここでは名前をデフォルトの「Function1.cs」としました。

f:id:daigo-knowlbo:20170814015604p:plain

「New Templates - Function1」というファンクションのトリガーを選択するウィンドウが表示されます。

f:id:daigo-knowlbo:20170814015713p:plain

「HttpTriggerWithParameters」を選択します。
また、「AccessRights」を「Anonumouse」としました。これにより、トリガーとなるHTTPリクエストを行う際に認証なしとなります(テストの利便性の為ここではそうしていますが、誰でもHTTPトリガーをキックできてしまうということなので、ご利用には気を付けてください)。
「FunctionName」はデフォルトの「HttpTriggerWithParametersCSharp」とします。

自動生成された Function1.cs 配下の通りです(リスト1)。

//リスト1 自動生成されたFunction1.cs

using System.Linq;
using System.Net;
using System.Net.Http;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;

namespace FunctionApp1
{
  public static class Function1
  {
    [FunctionName("HttpTriggerWithParametersCSharp")]

    public static HttpResponseMessage Run(
      [HttpTrigger(
        AuthorizationLevel.Anonymous, 
        "get",
        "post", 
        Route = "HttpTriggerCSharp/name/{name}")]
      HttpRequestMessage req, 
      string name, 
      TraceWriter log)
    {
      log.Info("C# HTTP trigger function processed a request.");

      // Fetching the name from the path parameter in the request URL
      return req.CreateResponse(HttpStatusCode.OK, "Hello " + name);
    }
  }
}

Run()メソッドがFunctionのエントリーポイントです。
第1引数「HttpRequestMessage req」に「[HttpTrigger]属性」が付与されています。HttpTrigger属性のパラメータで以下の設定が宣言されています。

(3) CosmosDB入力バインド実装の追加

まず、CosmosDB入力バインド用エクステンションを NuGetパッケージ より追加します。

ソリューションエクスプローラで FunctionApp1 をマウス右ボタンクリック。
表示されたメニューから「NuGet パッケージの管理」を選択します。

f:id:daigo-knowlbo:20170814021042p:plain

「NuGet パッケージの管理」画面が表示されたら、「参照」タブを選択し「Microsoft.Azure.WebJobs.Extensions.DocumentDB」を検索します。

f:id:daigo-knowlbo:20170814021317p:plain

Microsoft.Azure.WebJobs.Extensions.DocumentDB」を選択して、インストールボタンをクリックします。

では、 Function1.cs を開き、以下のように編集します。

// リスト2 CosmosDB入力バインド処理を追加したFunction1.cs

using System.Linq;
using System.Net;
using System.Net.Http;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;

namespace FunctionApp1
{
  public static class Function1
  {
    [FunctionName("HttpTriggerWithParametersCSharp")]

    public static HttpResponseMessage Run(
      [HttpTrigger(
        AuthorizationLevel.Anonymous, 
        "get",
        "post", 
        Route = "HttpTriggerCSharp/name/{name}")]
      HttpRequestMessage req,
      [DocumentDB(
        "CompanyDB", 
        "EmployeeCollection",
        ConnectionStringSetting = "cosmosdb_DOCUMENTDB", 
        Id = "{name}")]
      dynamic document,
      string name, 
      TraceWriter log)
    {
      log.Info("C# HTTP trigger function processed a request.");

      // 入力ドキュメントをログ出力
      log.Info("input document info");
      log.Info(" firstname:" + document.firstname);
      log.Info(" lastname:" + document.lastname);

      // 入力ドキュメントに変更を加える
      document.age = 25;
      document.Salary = 15000000;

      // Fetching the name from the path parameter in the request URL
      return req.CreateResponse(HttpStatusCode.OK, "Hello " + name);
    }
  }
}

Function1.csへの修正ポイントは以下の通りです。

  • 引数「document」の追加
    HttpTrigger引数に続けて「document引数」を追加しています。これが CosmosDB入力バインドパラメータになります。
    パラメータには「DocumentDB属性」を付与しています。
    入力バインドの情報として「データベース名」「コレクション名」を指定しています。
    「ConnectionStringSetting」は、Cosmos DBへの接続文字列情報です。接続文字列自体ではなく、接続文字列を設定した「構成情報キー」を指定します(設定方法は後述)。
    「Id」は、入力バインドするCosmos DBドキュメントの ID を表します。ここでは「{name}」としていますが、これはHttpTriggerのパラメータ「{name}」に該当します。「nameパラメータ値 = ドキュメントID」と、意味的に少し変ですが、自動生成コードの修正を最小限にしています。

  • documentのログ出力
    document引数には ID に該当するドキュメント オブジェクトが自動的にバインド設定されて呼び出されます。
    document.firstname / document.lastname をログ出力することで、内容を確認できるようにしています。

  • documentへのプロパティ値追加
    以下のようにdocumentに対して変更を加えています。
    入力バインドしたドキュメントへの変更は、Functionの正常終了後に Cosmos DBドキュメント に反映されます(データ更新が行われます)。

// 入力ドキュメントに変更を加える
document.age = 25;
document.Salary = 15000000;

(4) 公開 & Azureポータルでの構成

では、Azure上に公開します。

ソリューションエクスプローラで FunctionApp1 をマウス右ボタンクリック。
表示されたメニューから「公開」を選択します。

f:id:daigo-knowlbo:20170814022920p:plain

「新規作成」を選択して「発行」ボタンをクリックします(既にAzure FunctionsをAzure上に作成済みの場合には、「既存のものを選択」を利用します)。

f:id:daigo-knowlbo:20170814022953p:plain

Functionの名前等は適当に・・・ここでは Function Appの名前を InputBindExample として、「リソースグループ」「App Service プラン」「ストレージアカウント」は、それぞれ新規作成しました。

f:id:daigo-knowlbo:20170814023745p:plain

「公開」が成功した後の、Azureポータル画面が以下となります。
「Azure Functions(App Service)」「App Service Plan」「ストレージアカウント」の3つのリソースが作成されました。

f:id:daigo-knowlbo:20170814023859p:plain

Azure Functions「InputBindExample」を選択します。
「アプリケーション設定」をクリックして、Cosmos DBへの接続文字列項目を追加します。

f:id:daigo-knowlbo:20170814023941p:plain

f:id:daigo-knowlbo:20170814024043p:plain

(5) 実行

では、Functionを実行してみます。
まず、Azureポータルから実行します。

Function「HttpTriggerWithParametersCSharp」を選択します。
そして右側のテストタブを表示し、パラメータ「name」に「0000000001」を設定します。これは「入力パラメータname = ドキュメントID」として実装しているためです。
実行ボタンをクリックします。

f:id:daigo-knowlbo:20170814030723p:plain

出力されたログが以下の通りです。
ID = 0000000001 のドキュメント内容 firstname / lastname が出力されていることを確認することができます。つまり、確かにCosmos DBドキュメントが入力バインドパラメータとして引き渡されました。

f:id:daigo-knowlbo:20170814030753p:plain

次にAzureポータルで、Cosmos DBの「データエクスプローラ」を表示します。
age / salary 項目が追加されていることが確認できます。

f:id:daigo-knowlbo:20170814030920p:plain

匿名認証OK、HTTP GET許可としている為、ブラウザで「Https://inputbindexample.azurewebsites.net/api/HttpTriggerCSharp/name/0000000001」をアクセスする事でもFunctionをキックすることができます。

f:id:daigo-knowlbo:20170814033200p:plain

4 まとめ

ということで、Azure FunctionsへのCosmos DB入力バインドでした。
入力バインドといっても、Functionsの処理内でCosmos DBドキュメントに対して変更を加えることもできました。

Azure Functionsへの入出力バインドはCosmos DB以外にも「Blob storage」だったり、「Queue storage」だったりと、たくさんのバリエーションがあります。これらのバインドを利用すると、従来型の定型的ロジックの記述を省略することができます。
今回のCosmos DBバインドの例では、Cosmos DBへの接続処理の記述、取得・更新処理 の記述といったものが不要となりました。
つまり、煩雑なロジックの記述が Azure上のプラットフォームインフラ に吸収されていることにより、開発者はビジネスロジックの記述に注力することが可能になります。

本投稿では、ローカル実行やデバッグ等、色々端折っておりますが、Azure FunctionsへのCosmos DB入力バインドの一例として参考になればと思います。

「Serverless Meetup Tokyo #4」に参加した話

2017/8/9 「Serverless Meetup Tokyo #4」に参加してきました。

serverless.connpass.com

4回目の開催ということですが、私は初めての参加になりました。
すんごい人気なので、#5も今の時点で満員状態のようです(補欠当選も十分あるので、興味があれば、溢れてても登録しておいて損はないと思います。私も #4 では補欠繰り上げしたので^^)。

Azure勢 と AWS

で、私はこのブログを見てもわかる通り、いわゆる「Azure勢」です。
そして、この「Serverless Meetup Tokyo」は「AWS勢」が主軸です。

基本的には「Azure勢」とか「AWS勢」とか線引きをするべきではないし、したくないのですが、現在の多様化した技術世界においては、Azure / AWS の両方の技術をくまなく把握する人間というのは、ある意味限られた優秀な方々なのだと思っています。私のような凡人は、片方、もしくは両方に触手を伸ばしたとしても、どちらかに偏る事になるのだと思っています。
そして、一方に完全に偏ったとしても「Azureのすべてを知る」「AWSのすべてを知る」これ自体が非常に困難なほどの状況ではないかと思ってもいます。

楽しかったのですよ

そんな中での「Serverless Meetup Tokyo #4」だったのですが・・・

結論としては非常に楽しめました!

あのー、Azure系イベントに参加するよりも、もしかしたら(ある意味)楽しかったかも・・・これは、きちんと説明しないと語弊があるのだけれど・・・

私自身、Azureについては日々勉強を重ねています。
ですので、Azure系イベントでは、やはり「既知の領域」というものが大きくなってしまいます(あー、そんな偉そうなこと言える程ではないのだけれど・・・ご勘弁をm(_ _)m)。

しかし、AWSについては「完全な無知」ではないにしても「知らない領域」が広く存在しています。
ですから、自分自身にとって知らないことが多く、

  • 「へー、そうなんだー」

とか

  • 「このサービスはAzureでは何に該当するの?」

とか、はたまた、

  • 「あれ!?AWSだとこんな問題があるの?もしかしてAzureだと、この機能を使ったら解決出来てるんじゃないかなぁ」

とかいろいろ興味深いお話を聞くことができます。

結局・・・

そして、各セッションに対する感想はそれぞれあったのですが、今私はお酒も入っているのでざっくり、個人的総括で締めさせていただきます!

  • 「”サーバーレス アーキテクチャ”、全然 実践投入 いけるじゃん!」という自信を持てた
  • そうそう、やっぱり NoOps こそ目指すべき道だよ!人的リソースを運用メンテにかけるより顧客へのValueの提供にかけるべきだよ!

あと、個人的思い・・・

  • 20代のフレッシュエンジニアも、40代のおっさんエンジニア(&マネージャ)も楽しめて、より多くのValueを生成出来て、売上・実利を上げられる仕事がしたいよ

そして、今日のセッションでは得られていない、ビジネス的興味、そして整理したい点は以下。

  • ServerLessやPaaSを使うことのコストメリットについての整理

ではではー。
いつものブログとちょっと違うテイストになっちゃったかも・・・

【Cosmos DB】有効期限(TTL)で自動削除されるデータを作る

1 概要

Cosmos DBでは「有効期限付きデータ(ドキュメント)」というものを作ることができます。
ログ情報とかユーザーセッション情報とかのデータを ドンドコドンドコ 投入して、一定期間経過したデータは自動で削除するようなケースで利用可能です。

「よくあるファイル転送サービス(一定期間で削除される)」だったり「スナップチャット(的な)有効期限で自動削除されるサービス」だったり、そんなところでも使えるケースがあるかと思います。

ただし、ドキュメントが単独で自動削除される機能であるため、「一連の関連データを削除」というようなケースでは、単純に適用することはできないと思います。

1つ、特徴として「自動削除では RU は発生しない(RUは消費しない)」という点があります。

自前プログラムで、裏側でバッチ削除的なことをする場合、RUを消費するので、上手く使えばメリットのある機能になると思います。

1.1 設定レベル

有効期限の設定は、以下の2つのレベルに対して設定可能です。

  • 「コレクション」に対して設定する
  • 「ドキュメント」に対して設定する

1.1.1 「コレクション」に対して設定する

「Off / On(no default) / On」の3つの設定から選択します。

(1) Off

Off は、このコレクションにおけるドキュメントの有効期限自動削除を無効にします。ドキュメントに対して明示的に有効期限を設定しても、自動削除機能は働きません。

(2) On(no default)

On(no default) は、このコレクションにおけるドキュメントの有効期限自動削除を有効にします。既定の有効期限時間は設定しません。
有効期限削除を有効にしたいドキュメントに対して、明示的に時間を設定します。

(3) On

On は、このコレクションにおけるドキュメントの有効期限自動削除を有効にします。既定の有効期限時間も設定します。
既定の有効期限は、各ドキュメントでオーバーライドすることが出来ます。

また、有効期限は「秒」単位で設定可能です。

1.1.2 「ドキュメント」に対して設定する

ドキュメントに対して有効期間を設定する場合は、保存するドキュメントオブジェクトに対してJSONプロパティ名=「ttl」というint?型プロパティを追加します。

 [JsonProperty(PropertyName = "ttl", 
  NullValueHandling = NullValueHandling.Ignore)]
 public int? TimeToLive { get; set; }

※後述リスト3が完全版オブジェクト実装

1.1.3 「コレクション設定」「ドキュメント設定」の相関関係

コレクションに対する設定とドキュメントに対する設定の相関関係を表にまとめると以下の通りです。

コレクション設定 = Off コレクション設定 = On(no default) コレクション設定 = On(既定値 n秒)
ドキュメント設定 = なし 有効期限削除は無効(削除されません) 有効期限削除は無効(削除されません) 最終更新日時からn秒後に削除されます
ドキュメント設定 = -1 有効期限削除は無効(削除されません) 有効期限削除は無効(削除されません) 有効期限削除は無効(削除されません)
ドキュメント設定 = m 有効期限削除は無効(削除されません) 最終更新日時からm秒後に削除されます 最終更新日時からm秒後に削除されます

※「ドキュメント設定 = xx」と記述しましたが、コード上では int? 型として有効期限(TTL)を指定する事ができます。

1.2 削除タイミング

削除のタイミングは以下となります。

ドキュメントが最終更新されてから、
有効期限として設定された時間(秒)が経過したタイミング   

「最終更新日時(Last modified timestamp)」からの経過時間で自動削除判定が行われます。
「最終参照日時」ではないので、単純に ”一定期間利用されていないデータを削除する” といった用途には適用できないのでご注意を。

1.2.1 最終更新日時(Last modified timestamp)とは

最終更新日時(Last modified timestamp)とは、具体的には以下のものを指します。

ドキュメントの「_ts」値  

_ts値は、ドキュメントに対してCosmos DBシステムによって設定される値です。
ドキュメントの最終更新日時を表し、ドキュメントの作成時・ドキュメントの更新時に自動的に更新されます。
値は、「UNIX時間」であらわされます。

Azureポータルのデータエクスプローラでドキュメントを参照すると、以下のように _ts 値を確認することができます。

f:id:daigo-knowlbo:20170804191841p:plain

Fiddlerでドキュメント取得を行うRESTリクエストをキャプチャしても、以下のように _ts 値を確認することができます。

f:id:daigo-knowlbo:20170804191814p:plain

2 実装(コード)

では具体的な実装(コード)で「ドキュメントの有効期限設定」を行う方法を説明します。

2.1 コレクションに対して有効期限を設定する

まず「コレクションに対して」有効期限を設定する方法になります。

// リスト1 コレクションに対してドキュメントの有効期限を設定

private DocumentClient client = new DocumentClient(
  new Uri("https://cosmosdb.documents.azure.com:443/"), // あなたのURLを設定してね
  "【キー】"); // あなたのキーを設定してね

var database = 
  await client.CreateDatabaseIfNotExistsAsync(
    new Database() { Id = "ExampleDb" });
  
var collection = 
  await client.CreateDocumentCollectionIfNotExistsAsync(
    UriFactory.CreateDatabaseUri("ExampleDb"),
      new DocumentCollection()
      {
        Id = "ExampleCollection",
        DefaultTimeToLive = 60
      });

上記リスト1はデータベース(ExampleDb)とコレクション(ExampleCollection)を「(存在しなければ)新規作成」するロジックとなります。
そして、「DefaultTimeToLive = 60」の部分が「コレクションに対する、ドキュメント有効期限設定」になります。
つまり、最終更新日時から60秒でドキュメントが自動削除される設定となります。
「未設定 もしくは null」を設定すると、「Off」となります。

        DefaultTimeToLive = null

「-1」を設定すると、「On(no default)」となります。

        DefaultTimeToLive = -1

2.1.1 DocumentCollection.DefaultTimeToLive と 「Off / On(no default) / On」設定

コレクションに対する有効期限設定(DocumentCollection.DefaultTimeToLive)と「Off / On(no default) / On」の概念的設定の関連性は以下の通りとなります。

  • DocumentCollection.DefaultTimeToLive = n
    「On(no default)」に該当します。
    ドキュメントは、最終更新日時のn秒後に自動削除されます。

  • DocumentCollection.DefaultTimeToLive = null
    「Off」に該当します。

  • DocumentCollection.DefaultTimeToLive = -1
    「On(no default)」に該当します。
    ドキュメントの自動削除は有効ですが、自動削除時間はドキュメントの設定に依存します。

2.2 ドキュメントに対して有効期限を設定する

「個々のドキュメントに対して」有効期限を設定する例が以下のリスト2になります。

// リスト2 自動削除までの時間=100秒のドキュメントを作成

// コレクションに保存するオブジェクトを作成
UserAccount userAccount = 
  new UserAccount() { 
    UserID = "ryuichi111std", 
    UserName = "Ryuichi Daigo", 
    UpdateCount = 0, 
    TimeToLive=100 };

// オブジェクトをコレクションに保存(ドキュメントとして保存)
var document = await client.CreateDocumentAsync(
  UriFactory.CreateDocumentCollectionUri("ExampleDb", "ExampleCollection"),
  userAccount);

Cosmos DB(DocumentDB)に保存するデータ型「UserAccount」が唐突に登場していますが、これは以下のリスト3の型となります。
「TimeToLiveプロパティ」値が有効期限(TTL)となります(ドキュメントの有効期限は100秒)。
リスト3にあるように「jsonプロパティ名 = ttl」とします。これがドキュメントの有効期限を示すプロパティとなります。

// リスト3 保存するドキュメントの型はこれ

using System;
using Newtonsoft.Json;

namespace AutoExpireDataExample
{
  public class UserAccount
  {
    [JsonProperty(PropertyName = "id")]

    public string UserID { get; set; }

    public string UserName { get; set; }

    public int UpdateCount { get; set; }

    [JsonProperty(PropertyName = "ttl", NullValueHandling = NullValueHandling.Ignore)]
    public int? TimeToLive { get; set; }
  }
}

3 まとめ

ということで「有効期限で自動削除されるデータ(ドキュメント)」についてのエントリーでした。
ドキュメントの削除処理に関したは「単に特定コレクションドキュメントが単独で消えていい例」それから「プログラマティックに関連データも同時にカスタム実行により削除したい例」とあると思います。
その上で、RU消費のない「ドキュメントの有効期限自動削除」は魅力的な機能でもあります。
使いどころの難しさはありますが、うまく活用すれば有益な機能の1つであると思います。

<2017年8月版>Xamarin + Prism 超入門(とりあえず動かしてみよう!)

最近の本ブログへのトラフィックのうち、以前に書いた以下の記事へのものが未だに多いようです。

ryuichi111std.hatenablog.com

ただし、上記記事では開発環境が Visual Studio 2015 であり、少し古いバージョンをベースとしています。

その為、[2017年8月版]として最新の開発環境である「Visual Studio 2017(Windows)」をベースに「Xamarin + Prism 超入門(とりあえず動かしてみよう!)」を書き起こしたいと思います(厳密には Xamarin Forms + Prism です)。

1 前提条件

本編に入る前・・・以下を前提条件とします。

  1. Visual Studio 2017がインストールされている事(Windowsの場合)
  2. Visual Studio 2017において「.NETによるモバイル開発」がインストールされている事
  3. iOS / Android / UWP(VS2017のみ) 実行環境が整っている事

2 はこれ↓です。

f:id:daigo-knowlbo:20170803012230p:plain

3 については本エントリーの主題ではありませんが、Xamarin開発を始める際に引っかかる事が多い点なので、いくつかのポイントを以下に説明しておこうと思います。

1.1 iPhoneシミュレータ(iOS)実行環境設定について

Mac側およびVisual Studio 2017側で設定を行います。

1.1.1 Mac側セキュリティ設定の変更

まず、Mac側でセキュリティに関する設定を行う必要があります。
「システム環境設定」ウィンドウで「共有」をクリックします。

f:id:daigo-knowlbo:20170803012705p:plain

「共有」ウィンドウで「リモートログイン」を有効に設定します。

f:id:daigo-knowlbo:20170803012732p:plain

これにより Visual Studio 2017側 から Mac側 へのアクセスが可能になります。
(Macとの接続がとられていないと、iOSアプリの実行・デバッグが行えません)

1.1.2 Visual Studio 2017からの接続設定

Visual Studio 2017のメニュー「ツール → iOS → Xamarin Mac Agent」を選択します。
「Xamarin Mac Agent」ウィンドウが表示されるので、「次へ」をクリックします。

f:id:daigo-knowlbo:20170803012839p:plain

Macが同一ネットワーク上に存在すればリストに表示されます。
接続したいMacを選択して「接続」ボタンをクリックします。

f:id:daigo-knowlbo:20170803012929p:plain

ログイン情報を入力して「ログイン」ボタンをクリックします。

f:id:daigo-knowlbo:20170803013024p:plain

以上で、Visual Studio 2017からMacへの接続設定が完了しました。

1.2 Androidエミュレータ実行環境設定について

初期設定として行うべきことが多く躓きやすいと思います(私もXamarinやり始めのころかなり躓きました・・・)。
まず前提として、Androidエミュレータは HAXM(Intel Hardware Accelerated Execution Manager) を使って実行します。そうでないと使い物にならないほど激遅です。
で、HAXMを動作させるには「Hyper-Vを無効化」しておかなければなりません。

1.2.1 Hyper-Vの無効化

Windowsの機能として「Hyper-V」をインストールしていなければ気にする必要はありません。
Hyper-Vがインストールされている場合には、以下のコマンドによりHyper-Vを無効化します。

bcdedit /set hypervisorlaunchtype off

※コマンド実行後は、再起動により設定が反映されます。

逆にHyper-V機能を有効化するには以下のコマンドを実行します(要再起動)。

bcdedit /set hypervisorlaunchtype auto

1.2.2 Google APIs Intel x86 Atom System Image と HAXM のインストール

エミュレータイメージである「Google APIs Intel x86 Atom System Image」と、「HAXM」をインストールします。
Visual Studio 2017のメニューから「ツール → AndroidAndroid SDK マネージャー」を選択します。

f:id:daigo-knowlbo:20170803013723p:plain

表示された「Android SDK Manager」から、以下を選択して「Install xx packages..」ボタンをクリックします。

f:id:daigo-knowlbo:20170803024247p:plain
f:id:daigo-knowlbo:20170803024306p:plain

HAXMの方は「Not compatible with Windows」と表示されてインストールできない場合があります。
その場合は以下から直接ダウンロードしてインストールを行います。

software.intel.com

zipファイルをダウンロードし、解凍して生成された「intelhaxm-android.exe」を実行することでHAXMのインストールが行われます。

f:id:daigo-knowlbo:20170803013951p:plain

1.3 UWP実行環境設定について

Windows 10の「スタートメニュー → 設定 → 更新とセキュリティ → 開発者向け」を選択します。
「開発者向け機能を使う」項目から「開発者モード」を選択します。

f:id:daigo-knowlbo:20170803014052p:plain

しばらく待つとインストールが完了します。

2 Visual Studio 2017 で Xamarin + Prism 開発

やっと本題です。

Visual Studio 2017を起動します。

2.1 「Prism Template Pack」のインストール

メニュー「ツール → 拡張機能と更新プログラム」を選択します。

f:id:daigo-knowlbo:20170803014331p:plain

拡張機能と更新プログラム」ウィンドウが表示されます。

「オンライン」を選択し、右上の検索ボックスに「Prism Template Pack」と入力します。
一覧に表示された「Prism Template Pack」を選択し「ダウンロード」ボタンをクリックします。
ダウンロードが完了したら、「閉じる」ボタンをクリックします。

f:id:daigo-knowlbo:20170803014426p:plain

Visual Studio 2017を終了させます。

「Prism Template Pack」のインストール画面が表示されます。

f:id:daigo-knowlbo:20170803014512p:plain

インストール画面の指示に従うことで、インストールが完了します。

f:id:daigo-knowlbo:20170803014526p:plain

2.2 Prismプロジェクトの作成

Visual Studio 2017を起動します。
メニュー「ファイル → 新規作成 → プロジェクト」を選択します。

f:id:daigo-knowlbo:20170803014613p:plain

プロジェクトテンプレート(カテゴリー)として「Prism」が追加されていることを確認することができます。

f:id:daigo-knowlbo:20170803014657p:plain

ここでは「Prism → Xamarin.Forms」を選択します。以下の4つのテンプレートがリストされます。

  • Prism Autofac App(Xamarin.Forms)
  • Prism Dryloc App(Xamarin.Forms)
  • Prism Ninject App(Xamarin.Forms)
  • Prism Unity App(Xamarin.Forms)

名称から分かるように、テンプレートごとに「利用するDIコンテナ」に違いがあります。
お好みで選択してOKですが、ここでは「Prism Autofac App(Xamarin.Forms)」を選択することにします。
名前はデフォルトのまま「PrismAutofacApp1」としました。
「OK」をクリックします。

「PRISM PROJECT WIZARD」ウィンドウが表示されます。

f:id:daigo-knowlbo:20170803014805p:plain

ターゲットとするプラットフォームの選択になります。ここでは iOS / ANDROID / UWP の3つすべてを選択します。

Macとの接続設定が未設定の場合は「Xamarin Mac Agentの指示」ウィンドウが開きます。
ネットワーク内に開発に使えるMacがある場合は接続します。
Macとの接続設定が済んでいる環境では、このステップは省略されます)

f:id:daigo-knowlbo:20170803015005p:plain

「新しいユニバーサル Windows プロジェクト」ウィンドウが表示されます。

f:id:daigo-knowlbo:20170803015130p:plain

UWPのターゲットバージョンの指定になりますが、ここではデフォルトのまま「OK」ボタンをクリックすることとします。

以上でプロジェクトの作成が完了します。

2.3 実行

では、ソースは何もいじらずに、ウィザードによって生成されたHello World的なプログラムを実行してみます。

2.3.1 Androidエミュレータで実行

VS上部のツールバー(?)から「スタートアッププロジェクト」を「PrismAutofacApp1.Droid」を選択します。
すぐ右のドロップダウンでシミュレータデバイスを選択します。ここでは「Visual Studio_android-23_x86_phone(Android 6.0 - API 23)」を選択します。

f:id:daigo-knowlbo:20170803020110p:plain

F5キークリックでデバッグ実行を行います。
ビルド&デプロイが行われ、以下のエミュレータ画面が表示されます。

f:id:daigo-knowlbo:20170803020132p:plain

※私の環境ではデプロイが完了しない場合があります。そんな場合は、一度ビルドのキャンセルを行い、再度F5をクリックするとうまく動作したりするようです。

2.3.2 iPhoneシミュレータ(iOS)で実行

VS上部のツールバー(?)から、「ソリューション プラットフォーム」を「iPhoneSimulator」に、「スタートアッププロジェクト」を「PrismAutofacApp1.iOS」に設定します。
すぐ右のドロップダウンでシミュレータデバイスを選択します。ここでは「iPhone 7 iOS 10.3」」を選択します。

f:id:daigo-knowlbo:20170803020549p:plain

F5キークリックでデバッグ実行を行います。
ビルド&デプロイが行われ、シミュレータ画面が表示されます。

Visual Studio 2017の「リモート Simulator から Windows へ」機能が有効になっている場合は、Windows側の画面にシミュレータが表示されます。この機能が無効になっている場合には、Mac側にシミュレータ画面が表示されます。

[Windows側にシミュレータ表示]
f:id:daigo-knowlbo:20170803022544p:plain

[Mac側にシミュレータ表示]
f:id:daigo-knowlbo:20170803022450p:plain

「リモート Simulator から Windows へ」機能の設定変更は以下の通りです。
Visual Studio 2017のメニュー「ツール → オプション」を選択し、「オプション」ウィンドウを開きます。

f:id:daigo-knowlbo:20170803022835p:plain

左側のカテゴリーから「Xamarin → iOSの設定」を選択します。右側に表示される「リモート Simulator から Windows へ」チェックボックスで有効・無効の設定を切り替えます(当該機能はVisual Studio Enterpriseのみの機能になります)。

2.3.3 UWPで実行

VS上部のツールバー(?)から、「ソリューション プラットフォーム」を「x64(もしくはx86)Any CPU」に、「スタートアッププロジェクト」を「PrismAutofacApp1.UWP(Universal Windows)」に設定します。
すぐ右のドロップダウンでシミュレータデバイスを選択します。ここでは「ローカル コンピューター」を選択します。  

f:id:daigo-knowlbo:20170803074041p:plain

F5キークリックでデバッグ実行を行います。
以下のようにUWPアプリが起動します。

f:id:daigo-knowlbo:20170803023310p:plain

※2017/8/3 かずき@69.7kg (@okazuki) | Twitterさんより「ソリューションプラットフォーム」を AnyCPU ではなく x64 もしくは x86 を明示的に選択すれば「配置」の必要がないことをご指摘いただきました。「2.3.3 UWPで実行」に関する 以下の取り消し線部分を上記に修正しました!かずきさんありがとうございます!

配置→実行の手順となります。

(1) 配置

ソリューションエクスプローラから「PrismAutofacApp1.UWP」を選択し、マウス右ボタンクリックでポップアップメニューを表示、「配置」メニューを選択します。

f:id:daigo-knowlbo:20170803023005p:plain

ビルドが行われ、配置処理が行われます。

(2) 実行

VS上部のツールバー(?)から、「ソリューション プラットフォーム」を「Any CPU」に、「スタートアッププロジェクト」を「PrismAutofacApp1.UWP(Universal Windows)」に設定します。
すぐ右のドロップダウンでシミュレータデバイスを選択します。ここでは「ローカル コンピューター」を選択します。  

f:id:daigo-knowlbo:20170803023228p:plain

F5キークリックでデバッグ実行を行います。
以下のようにUWPアプリが起動します。

f:id:daigo-knowlbo:20170803023310p:plain

まとめ

ということで、コーディング0の「Xamarin + Prism 超入門」でした。
Xamarinまわりは、以前と比べてかなり改善されていますが、初期設定関連の取り掛かりの部分が躓きとなる可能性がある部分だと思います。
ということで、Xamarin + Prism開発、更にはその手前の初期設定に関して少しでも本エントリーが参考になればと思います。

Azure FunctionsからCosmos DBに出力バインドする(2)~.csコンパイル編

1. はじめに

前回のエントリーに引き続きの投稿になります。
Azure Functions 出力バインドを利用し Cosmos DB にデータ出力を行います。

f:id:daigo-knowlbo:20170718235801p:plain

前回はAzureポータルのみでFunctionsの作成を行いました。
また、ソースコードの実装は .csx(C#スクリプト) をポータル上で編集しました。

今回は .csファイル で実装を行い、コンパイルアセンブリをAzure Functionsに発行することにします。
.csxでの実装に比べ、実行時コンパイル処理が省かれるので、起動時の動作が早くなります。

本エントリーのみでも理解できる内容として記述しますが、前回のエントリーと重複する部分は手短に記述します。ということで、前回のエントリーを見ていただけるとより理解しやすいかと思います。

ryuichi111std.hatenablog.com

2. 開発環境

コンパイル実装をするため、本エントリーでは以下の環境を利用します。

※ 2017/7/20現在、Stableな Visual Studio 2017 では 「Function Tools for Visual Studio 2017」がサポートされていません。

3. 前提条件

以下のAzure環境を前提条件とします。

3.1 Cosmos DB アカウント

以下のような 出力先 Cosmos DB アカウント を用意している前提とします。

f:id:daigo-knowlbo:20170720054830p:plain

API(データモデル)は「SQL (DocumentDB)」です。

3.2 Function App

前回エントリーで作成した以下の「Function App」を用意している前提とします。

f:id:daigo-knowlbo:20170720054951p:plain

「アプリ名」:RdExampleFunctionApp
「リソースグループ」:RdExampleFunctionApp
ホスティングプラン」:従量課金プラン
「場所」:西日本
「Storage」:新規作成 rdexamplefunctionapp

4. ② VS2017 Preview(Ver.15.3)を使ったcsコンパイルによる実装

VSを使用した実装に移りますが、「4.1 基本的なAzure Functionsプロジェクトの作成から発行まで」と、その上に「4.2 osmos DB出力バインドの追加からパブリッシュまで」の2段階で進めたいと思います。

4.1 プロジェクトの作成から基本パブリッシュまで

まず第1段階として、基本的なAzure Functionsプロジェクトの作成から発行までを行います。

(1) Visual Studio 2017 Preview(15.3)の起動

Visual Studio 2017 Preview(15.3)を起動します。
「Azure Function Tools for Visual Studio 2017」のインストールを済ませておいてください。

(2) Azure Functionsプロジェクトの作成

「ファイル → 新規作成 → プロジェクト」を選択します。
「新しいプロジェクト」ウィンドウで、テンプレートカテゴリーから「Cloud」を選択、プロジェクトテンプレートとして「Azure Functions」を選択します。
プロジェクト名は、ここでは「CosmosDbBindExampleFunction」としました。

f:id:daigo-knowlbo:20170719185150p:plain

以下のようなプロジェクトが作成されます。

f:id:daigo-knowlbo:20170719185207p:plain

(3) Functionソース(.cs)の追加

新規作成したプロジェクトには、まだ1つもFunction実装がありません。
Functionの実装ソース(.cs)を追加します。
ソリューションエクスプローラでプロジェクト名「CosmosDbBindExampleFunction」をマウス右ボタンクリック。表示されたメニューから「追加 → 新しい項目」を選択します。

f:id:daigo-knowlbo:20170719185448p:plain

表示された「新しい項目の追加」ウィンドウから「Azure Function」を選択し、名前を入力します。ここではデフォルトのまま「Function1.cs」としました。

f:id:daigo-knowlbo:20170719185550p:plain

「New Azure Function」ウィンドウが表示されます。

f:id:daigo-knowlbo:20170719190323p:plain

ここでは、設定内容は以下とします。

  • トリガーの種類: HttpTrigger
  • AccessRights: Anonymous(今回は簡易に匿名で利用できるようにします)
  • FunctionName: HttpTriggerCSharp

自動生成された Function1.cs は以下の通りです。

// 自動生成された Function1.cs 

using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;

namespace CosmosDbBindExampleFunction
{
  public static class Function1
  {
    [FunctionName("HttpTriggerCSharp")]
    public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
    {
      log.Info("C# HTTP trigger function processed a request.");

      // parse query parameter
      string name = req.GetQueryNameValuePairs()
        .FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0)
        .Value;

      // Get request body
      dynamic data = await req.Content.ReadAsAsync<object>();

      // Set name to query string or body data
      name = name ?? data?.name;

      return name == null
        ? req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a name on the query string or in the request body")
        : req.CreateResponse(HttpStatusCode.OK, "Hello " + name);
    }
  }
}

(4) Nugetパッケージの更新

自動生成されたプロジェクトおよびfunction1.csは、2017/7/20現在の確認では、そのままではビルドが通りません。
Nugetパッケージの更新を行う必要があります。
ソリューションエクスプローラでプロジェクト名「CosmosDbBindExampleFunction」をマウス右ボタンクリック。表示されたメニューから「NuGetパッケージの管理」を選択します。

f:id:daigo-knowlbo:20170719190746p:plain

「更新プログラム」を選択、「プレリリースを含める」にチェック、「すべてのパッケージを選択」にチェックし、「更新」ボタンをクリックします。

f:id:daigo-knowlbo:20170719190950p:plain

(5) ビルド&発行

ソリューションエクスプローラでプロジェクト名「CosmosDbBindExampleFunction」をマウス右ボタンクリック。表示されたメニューから「発行」を選択します。

f:id:daigo-knowlbo:20170719193509p:plain

発行のUIが表示されるので「既存のものを選択」を選択して「発行」ボタンをクリックします(今回はAzureポータル上に既に RdExampleFunctionApp というFunction Appを作成済みの為)。

f:id:daigo-knowlbo:20170719193529p:plain

発行対象のFunction Appである「RdExampleFunctionApp」を選択して、「OK」ボタンをクリックします。

f:id:daigo-knowlbo:20170719193538p:plain

発行が完了したらAzureポータルでFunctionを確認します。
HttpTriggerCSharp関数が発行されて事を確認することができます。

f:id:daigo-knowlbo:20170719193555p:plain

4.2 Cosmos DB出力バインドの追加からパブリッシュまで

次に第2段階として、Cosmos DB出力バインドの追加を行います。

(1) DocumentDB Extensionの追加

Cosmos DBへの出力バインドを実装するために、以下のNuGetパッケージを追加します。

  • Microsoft.Azure.WebJobs.Extensions.DocumentDB

NuGetパッケージの管理画面から「Microsoft.Azure.WebJobs.Extensions.DocumentDB」を検索&選択して「インストール」を行います。

f:id:daigo-knowlbo:20170719192541p:plain

(2) Function1.csの実装を修正

Function実装を Cosmos DB出力バインド を行うように修正します。

// Cosmos DB出力バインド実装を加えた Function1.cs

using System.Linq;
using System.Net;
using System.Net.Http;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;

namespace FunctionApp2
{
  public static class Function2
  {
    [FunctionName("HttpTriggerCSharp")]
    public static HttpResponseMessage Run(
      [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]
      HttpRequestMessage req,
      [DocumentDB("CommunicationDB", "MessageCol",
            CreateIfNotExists = true,
            ConnectionStringSetting = "cosmosdb_DOCUMENTDB")]
      out object messageDocument,
      TraceWriter log)
    {
      string yourName = req.GetQueryNameValuePairs()
        .FirstOrDefault(q => string.Compare(q.Key, "yourName", true) == 0)
        .Value;

      string message = req.GetQueryNameValuePairs()
        .FirstOrDefault(q => string.Compare(q.Key, "message", true) == 0)
        .Value;

      // 出力パラメータmessageDocumentに設定された値がCosmos DBに出力される
      messageDocument = new
      {
        yourName = yourName,
        message = message
      };

      if (!string.IsNullOrEmpty(yourName) && !string.IsNullOrEmpty(message))
      {
        return req.CreateResponse(HttpStatusCode.OK);
      }
      else
      {
        return req.CreateResponse(HttpStatusCode.BadRequest);
      }
    }
  }
}

上記実装のうち重要なポイントを2つ以下に記述します。

①メインの Run() メソッドの引数

前回の.csxファイル形式での実装では、引数のバインドをAzureポータルのGUI上で行いました。
AzureポータルGUI上での操作は、実際には function.json ファイルに反映されます。つまり、GUI操作はエディタとしての機能であり、本質的には function.json への記述で設定を行いました。
コンパイルベースのFunction定義では、メソッド引数への属性設定により同様の設定を行います(つまり、引数属性設定により入出力バインドの設定を行うことができます)。

  • 第1引数

    [HttpTrigger(AuthorizationLevel.Anonymous, “get”, “post”, Route = null)] HttpRequestMessage req

入力のHttpTrigger定義となります。匿名ユーザーのアクセスを許可し、GET / POST を受け入れます。ルーティング定義はnullとしています。

  • 第2引数

    [DocumentDB(“CommunicationDB”, “MessageCol”, CreateIfNotExists = true, ConnectionStringSetting = “cosmosdb_DOCUMENTDB”)] out object messageDocument

こちらがCosmos DB出力バインドの定義になります。
CommunicationDBデータベース、MessageColコレクションへの出力としています。
CreateIfNotExists=trueは、本Functionの実行時にCosmos DB側のデータベース・コレクションが存在しなかった場合に自動生成するかどうかの設定です。ここでは、trueなので存在しなかったら作成する意味となります。
ConnectionStringSetting 値は、出力先のCosmos DBへの接続文字列を表します。ただし、接続文字列自体ではなく、接続文字列を設定したアプリケーション設定キーとなります。
アプリケーション設定キーは、Azureポータルで設定・確認することができます。
RdExampleFunctionAppを選択し、「アプリケーション設定」をクリックします。

f:id:daigo-knowlbo:20170720060303p:plain

「アプリ設定」項目に「キーと値」の設定が行えるので、ここに「cosmosdb_DOCUMENTDB」キーを追加し、値としてCosmos DBアカウントへの接続文字列を追加します(前回の.csx形式によるブログエントリーを実施している場合、既に当該キーは追加されていると思います)。

f:id:daigo-knowlbo:20170720060347p:plain

②Cosmos DB ドキュメントの作成

出力バインド定義が行われた引数 messageDocument をnewで生成することで、作成するCosmos DB(DocumentDB)ドキュメントを指定することができます。

messageDocument = new
{
yourName = yourName,
message = message
};

(3) 発行

VSから発行を行います。
※ 既に前述で発行方法は説明したので、ここでは割愛します。

(4) テスト実行

今回発行したFunctionはHttpTriggerで起動します。
匿名ユーザーによるリクエストも許可している為、以下のURLによりキックすることができます。

https://rdexamplefunctionapp.azurewebsites.net/api/HttpTriggerCSharp?yourName=ryuichi.daigo&message=hello azure functions

ブラウザで上記URLをリクエストします。

AzureポータルからCosmos DBのデータエクスプローラを確認すると、以下のようにドキュメントが作成されたことを確認することができます。

f:id:daigo-knowlbo:20170720060710p:plain

5 まとめ

Azure Functionsは、超基本でいうとあくまで「Function(関数)」なのですが、今回紹介したBindを含め、やはり色々な機能を持っています。最近ではDurable Functionsなんてのも出てきましたし。
そんな進化し続けるAzure Functionsですが、Visual StudioのToolkitのリリースはやや遅めな印象を持っています。とはいえ、そろそろ正式版も出るんじゃないかなあ・・・とも思うので、そのあたりの開発インフラ事情が更新されたら、本エントリーも改めて修正していきたいと思います。