AWS lambda C# & dynamodb ローカル開発環境

ゴールデンウィークなので、表題の件でもやるよ。Visual Studio 2019は適当にインストールされていることが前提だが、アホでもdynamodbにput/get出来るまで書くよ。とりあえず俺は、"ASP.NET と Web 開発", ".NET デスクトップ開発", ".NET Core クロスプラットフォームの開発"の3つを初期インストールで入れているが、後にゲームやりたくなったりなんだりで、違うことやりたくてもVisual Studio Installerで追加できるので問題はないぞ。aws cliは(これ見る人は入れていると思うけど)入っていることが前提。俺はこれ( https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-windows.html )のインストーラ使って入れてます。Python嫌いなので。

C:\>aws configure
AWS Access Key ID [None]: dummy
AWS Secret Access Key [None]: dummy
Default region name [None]: ap-northeast-1
Default output format [None]: json

テストでも必要になるので適当に設定。

amazonさんが提供するlocal用のdynamodbなのだけど、JRE(JDK)が必要なのです。俺は入れた覚えが全く無いのだが、下記バージョンが入っていた。ココらへんはawsのドキュメント見てくれ。あーーーんど、dynamodbの実行ファイル(jar)もあるのでダウンロードしてね。 https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html

下記は俺の環境。

E:\>java -version
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b18)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b18, mixed mode)

とりあえずE:に配置。コマンド面倒くさいのでバッチで書いて実行。

E:\dynamodb_local>start.bat

E:\dynamodb_local>java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb
Initializing DynamoDB Local with the following configuration:
Port:   8000
InMemory:       false
DbPath: null
SharedDb:       true
shouldDelayTransientStatuses:   false
CorsParams:     *

適当なテーブルとデータを作成してみましょうか。WindowsのCLIだとPythonのクソ野郎がエラー吐きまくる(let's encryptのcertbotで、nginxのconfig commentに2byte文字使った時と同じ)ので、ここでは日本語使いません。コマンドプロンプトをもう一窓開いて実行。

C:\>aws dynamodb create-table --table-name Posts --attribute-definitions AttributeName=Id,AttributeType=N AttributeName=Date,AttributeType=S --key-schema AttributeName=Id,KeyType=HASH AttributeName=Date,KeyType=RANGE --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1 --endpoint-url http://localhost:8000
{
    "TableDescription": {
        "AttributeDefinitions": [
            {
                "AttributeName": "Id",
                "AttributeType": "N"
            },
            {
                "AttributeName": "Date",
                "AttributeType": "S"
            }
        ],
        "TableName": "Posts",
        "KeySchema": [
            {
                "AttributeName": "Id",
                "KeyType": "HASH"
            },
            {
                "AttributeName": "Date",
                "KeyType": "RANGE"
            }
        ],
        "TableStatus": "ACTIVE",
        "CreationDateTime": 1556655253.192,
        "ProvisionedThroughput": {
            "LastIncreaseDateTime": 0.0,
            "LastDecreaseDateTime": 0.0,
            "NumberOfDecreasesToday": 0,
            "ReadCapacityUnits": 1,
            "WriteCapacityUnits": 1
        },
        "TableSizeBytes": 0,
        "ItemCount": 0,
        "TableArn": "arn:aws:dynamodb:ddblocal:000000000000:table/Posts",
        "BillingModeSummary": {
            "BillingMode": "PROVISIONED",
            "LastUpdateToPayPerRequestDateTime": 0.0
        }
    }
}

ここでputだのなんだの実行したいところですが、WindowsのCLIだとjson構文でエラー頻発するのでスルーします。bash on ubuntu on windowsだとか、git bushならうまくいくかもしれませんね。うまくいくんですが。とにかくPython嫌いなので先に進みます。コマンド例は下記。

// create table パーティションキー(HASH), ソートキー(RANGE)
aws dynamodb create-table --table-name Posts --attribute-definitions AttributeName=Id,AttributeType=N AttributeName=Date,AttributeType=S --key-schema AttributeName=Id,KeyType=HASH AttributeName=Date,KeyType=RANGE --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1 --endpoint-url http://localhost:8000

// table 一覧
aws dynamodb list-tables --endpoint-url http://localhost:8000

// table 詳細
aws dynamodb describe-table --table-name Posts --endpoint-url http://localhost:8000

// insert test data
aws dynamodb put-item --table-name Posts --item '{"Id":{"N":"1"},"Date":{"S":"20190419"},"Name":{"S":"Ayana Taketatsu"}}' --endpoint-url http://localhost:8000

// get item
aws dynamodb get-item --table-name Posts --key '{"Id":{"N":"1"}}' --endpoint-url http://localhost:8000

// get all item (scan)
aws dynamodb scan --table-name Posts --endpoint-url http://localhost:8000

ここからVisual Studioで新しいプロジェクトを作成。まずはブランクで起動(コード無しで続行)し、メニューの拡張機能のオンラインから"AWS Toolkit for Visual Studio 2017 and 2019"を入れる。入れたら閉じろ、だのダイアログが出たりなんだりするが指示通りで問題ない。ここらへんはnodeなんかと違って非常に親切なのでそのまま従う。で、終わったのなら早速Lambdaプロジェクトを作成する。新しいプロジェクトの作成->"AWS Lambda Project (.NET Core - C#)"だ。with Testsを選んでもいいが解説はしない。適当にディレクトリなどを指定して進む。AWS SDKが雛形を作る?とか聞いてくるが無視してemptyで作る。

メニューの表示->AWS Explorerで左窓を開いて、Edit ProfileのIDとKeyを"dummy"にしてOK。(上の方で設定したaws cliの値)

ソリューションエクスプローラから、ソリューションを右クリックして"ソリューションのNuGetパッケージの管理"を選択。検索するなりして"AWSSDK.DynamoDBv2"をプロジェクトにインストール。

ソリューションエクスプローラで"aws-lambda-tools-defaults.json"を開きリージョンだけ変更する。

{
  "Information" : [
    "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.",
    "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.",

    "dotnet lambda help",

    "All the command line options for the Lambda command can be specified in this file."
  ],

  "profile":"default",
  "region" : "ap-northeast-1",
  "configuration" : "Release",
  "framework" : "netcoreapp2.1",
  "function-runtime":"dotnetcore2.1",
  "function-memory-size" : 256,
  "function-timeout" : 30,
  "function-handler" : "AWSLambda1::AWSLambda1.Function::FunctionHandler"
}

本来なら複数クラスに分割するところですが、適当に3つのクラスにすべて記述する。ソリューションエクスプローラから"PostsEntity"クラスを新規作成。Function.cs, Status.csは下記。

PostEntity.cs

Function.cs

Status.cs

(20190501変更) ソースコードがうまく貼れないのでgithubに。
https://github.com/dobusarai2016/20190501lambda

(20190514) ソースと結果を読み返してみたらJsonっぽい文字列を返すというわけのわからんコードになっていますね……。FunctionHandlerはstringではなくClass Objectを返すようにするとLambdaSerializerが良きに計らってくれます。近日中に修正します。

うーーーーん、言語別に綺麗に整形するようにしたいなこれ。で、下のようにjsonが返ってくるのを確認。

データ例。

// Function Input:
# get
{
	"Id": 1,
	"Date":"20190501",
	"Method":"get"
}
# save
{
	"Id": 110,
	"Date":"20190501",
	"Name":"魑魅魍魎",
	"Method":"save"
}
# delete
{
	"Id": 110,
	"Date":"20190501",
	"Method":"delete"
}
# scan
{
	"Method":"scan"
}

DynamoというかNoSQLでの設計が未だによくわかっていないのですが、単なるKVSに見えるのでそもそもRDBMSみたいな使い方ではなくCMSのデータ置き場みたいに使うのかなこれ。簡単な業務アプリならいけそうだと思っていたのだけど検索難しいなー。

あ、Visual StudioさんはそのままLambdaをAWSに配置したりする機能があるようなのですが、個人ではアカウントを所有していないので試していません。連休明けに会社行ったら試そうかな。