前回から引き続き、 AWS Lambda を C# で、.NET Core 1.0、.NET Standard 1.6 を使って実装する際のメモです。 Autofac 使ってDIをする話がメインです。
(2017/9月時点での話=.NET Core 1.0しかサポートしてない時点です)
Overview
1 開発環境の準備 (その1)
2 .NET Core 1.0 対応の .NET Standard 1.6 のクラスライブラリの作成(その1)
3 簡易なクラスライブラリー実装(その1)
4 Console プロジェクトの作成 (←今回ココから)
5 Autofac の実装
6 AWS Labmda プロジェクトの作成
7 AWS Labmda の環境変数を読み込む
8 AWS API Gateway から Lambda - プロキシ統合 の使用とか
9 AWS Lambda から AWS Lambda の呼び出し
10 AWS Lambda から CloudWatch Events の呼び出し
4 Console プロジェクトの作成
デバッグでの動作確認用に、.NET Core のコンソールアプリを作ってしまいます。ソリューションエクスプローラーで、今回のソリューションを右クリック > 追加
> 新しいプロジェクト
をクリックします。
左ペインで「.NET Core」を選択して、「コンソールアプリ(.NET Core)」を選択しましょう(.NET Standardではなですよ)。プロジェクトの名前は、「LambdaDemo.ConsoleApp」にしました。
プロジェクトのターゲットフレームワークを変更します。ソリューションエクスプローラーで今作った「LambdaDemo.ConsoleApp」を右クリック > プロパティ
をクリックします。
表示された画面の左ペインの アプリケーション
で、ターゲットフレームワークを「.NET Core 1.0」にします。
そのままの画面で、左ペインの ビルド
をクリックし、一番下にある 詳細設定
をクリックします。
言語バージョンを「C#の最新のマイナーバージョン(最新)」に変更します。
文字化け対策
日本語はデフォルトだと文字化けするので拡張を入れておきましょう。
VS2017 の上部メニュー ツール
> NuGet パッケージ マネージャー
> ソリューションの Nuget パッケージ の管理
をクリックします。
(右上のクイック起動から「nu」と入力して起動したほうが早いですが...)
参照をクリックして、検索で「System.Text.Encoding.CodePages」を入力すると、そのパッケージが出てきます。ConsoleAppのプロジェクトのみにインストールします。
このプロジェクトのエントリーポイント、Program.cs のMain
メソッドの最初に、以下のコードを書いておきましょう。
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
async な Main メソッドへ変更
「LambdaDemo.ConsoleApp」プロジェクトの Program.cs を開きましょう。言語バージョンを上げたので、Main
メソッドを async 化できます。C#7.1 からの使える async Task Main Method です(あまり本編の内容とは関係ないのですがね...)。
元々のシグネチャ(以下)を、
static void Main(string[] args)
下のように変更しておきましょう。あー幸せ。
static async Task Main(string[] args)
(Taskを使ってるので、using System.Threading.Tasks;
も必要になります。)
(独り言ですが...結局以前やってたような MainAsyncメソッド作って Main メソッドから...GetAwaiter().GetResult() する手間とさ程変わりませんが...それでもこの機能は好きです)
スタートアップ プロジェクトに設定
ソリューションエクスプローラーで「LambdaDemo.ConsoleApp」プロジェクトを右クリック > スタートアップ プロジェクトに設定
をクリックします。これでデバッグ時はデフォルトでこのプロジェクトがデバッグされるようになりました。
5 Autofac の実装
そもそもIoCだったりDIとは?みたいなことは、ひとことでさらっと言って理解できるものではないと思うので省略。Nuitsさんの ここら辺とかいい勉強になると思います。
AWS Lambda 観点でいうと、環境変数を利用することができるので、最初からその想定でものを作っておいた方がよい(後で変更とか死ぬほどめんどい:個人的主観)。
環境変数の取得は、テストプロジェクトや動作確認用のConsole アプリではjsonファイルから呼び出すようにしておき、Lambda にデプロイしたときには、環境変数を取得するよう実装していきます。
Autofac 用のプロジェクト作成
ソリューションエクスプローラーで、今回のソリューションを右クリック > 追加
> 新しいプロジェクト
をクリックします。
.NET Standard のクラスライブラリを作ります。プロジェクトの名前は、「LambdaDemo.IoC」にしました。
.NET Standard1.6.0対応をします。やり方は前回同様で、 「ターゲットフレームワークの変更」と「csprojの編集」の2点です。
.NET Core 1.0 対応の .NET Standard 1.6 のクラスライブラリの作成
これを忘れると動かないのでご注意を。
NuGet で拡張をインストール
VS2017 の上部メニュー ツール
> NuGet パッケージ マネージャー
> ソリューションの Nuget パッケージ の管理
をクリックします。
(右上のクイック起動から「nu」と入力して起動したほうが早いですが...)
Autofac をインストールします。参照
をクリックし、検索で「autofac」と入れます。Autofacの最新版(今回だとv4.6.1)を、先程作った「LambdaDemo.IoC」プロジェクトだけにインストールします。
次は、環境変数の読み込みに必要な拡張を3つインストールします。
- Microsoft.Extensions.Configuration
- Microsoft.Extensions.Configuration.EnvironmentVariables
- Microsoft.Extensions.Configuration.Json
検索で「Microsoft.Extensions.Configuration」と入力すると出てきます。注意点として、.NET Standard1.6.0対応のバージョンは 3つとも v1.0.2 です(それぞれのライブラリの依存関係を見ると確認できます)。
3つとも、最新版ではなくバージョンを v1.0.2 にしてインストールしましょう。
プロジェクトの参照を追加
ソリューションエクスプローラーで「LambdaDemo.IoC」プロジェクトを右クリック > 追加
> 参照
をクリックします。
左ペインでプロジェクトをクリックし、「LambdaDemo.DemoService」を追加しましょう。
Container クラスの作成
「LambdaDemo.IoC」プロジェクトを右クリックし、追加
>クラス
をクリックします。クラス名は、「DemoContainer」としました。名前、安易につけると色んなライブラリと被って(壊れはしないけど)リーダビリティが落ちる場合があるので、意外に気を付けてます(今回はテキトーですが)
実装は、まずこんな感じで....
Autofac の基本的なところしか書いてないのざっくりとしか説明しませんが、DemoContainerクラスのstaticなコンストラクターで必要な情報を登録して、外からは34行目の Resolve<T>
メソッドを呼び出せばOKって流れです。
環境変数絡みのところは、19行目あたりは別の回で説明します。
コンテナーへの登録
48行目あたりの BuildContainer
メソッドを以下のように書き換えて、前回作成した SampleClass
を登録しましょう。
13行目~15行目を追加しています。SampleClass
を実装されているインターフェース(ISampleClass
)として登録、インスタンスのスコープは、InstancePerLifetimeScope
に設定という感じです。
スコープは、とりあえず InstancePerLifetimeScope
にしていますが、必要に応じて適切なスコープをせっていしましょう。詳しくは本家のドキュメントに。
Controlling Scope and Lifetime — Autofac 4.0 documentation
ConsoleApp で動作確認
「LambdaDemo.ConsoleApp」プロジェクトの Program.cs
を開いて以下のようにコーディングします。
2通りの呼び出し方をサンプルとして書いてますが、プロダクションでは用途に応じでって感じですね。
F5を押してデバッグ実行してみると、正しく動いてることが確認できます。
6 AWS Labmda プロジェクトの作成
いい加減、Lambda で動かしてしましょうか...という頃合いです。
プロジェクトの作成
ソリューションエクスプローラーで、今回のソリューションを右クリック > 追加
> 新しいプロジェクト
をクリックします。
左ペインで「AWS Lambda」をクリック > 「AWS Lambda Project(.NET Core)」を選択、プロジェクトの名前は、「LambdaDemo.Lambda」にしました。
AWS の「AWS Tookkit for Visual Studio 2017」が入ってない可能性があります。ここら辺を確認してみましょう。
AWS の「Select Blueprint」が表示されます。 「Empty Function」を選んで、Finish
ボタンをクリックします。
プロジェクトの参照追加
ソリューションエクスプローラーで「LambdaDemo.Lambda」プロジェクトを右クリック > 追加
> 参照
をクリックします。
追加するのは、「LambdaDemo.IoC」プロジェクトだけでOKです。
FunctionHandler メソッドのコーディング
AWS Lambda で入力パラメーターを受け取る場合、Lambda側でJSONをデシリアライズしてプログラムに渡してくれるってのがありますし、API Gateway 経由の場合、プロキシ統合の機能もあるので、それに応じてパラメーターの受け取り方を考える必要があります。
今回はシンプルに以下のJSONが入力される想定で実装します。
{ "key1": "value1" }
「LambdaDemo.Lambda」プロジェクトの「Function.cs」を開いて以下のように実装します。
まず、FunctionHandler
メソッドは、async
にします。今回は戻り値を返さないので、Task
を定義しています。
ちなみに、async のサポートは、本家のドキュメントで書かれています。
また、入力のパラメーター用に、Param
クラスを21行目で乱暴に定義してます。
AWS Lambda からこのプログラムに入力パラメーターが入ってくるとき、LambdaがJSONをデシリアライズしてメソッドの引数 param
にセットしてくれます。シリアライザーは、SDKの内部でJson.netを使ってるので、json のキャメルケースを .NET のクラスのパスカルケースにデシリアライズしてくれます。
15行目~16行目がビジネスロジックを呼び出すところとなりますが、これは ConsoleApp のプロジェクトでの呼び方と全く同じです。
デプロイ!の前に...
Lambda を作成するにあたっては、AWSのアカウント作ったりロール作ったりがあります。そこはまだのかたは本家ドキュメントを参考に...
さらに、VS2017の AWS Explorer でアカウントを設定しておきましょう。
AWS Toolkit for Visual Studio をセットアップする - AWS Toolkit for Visual Studio
デプロイ!
まず、「LambdaDemo.Lambda」プロジェクトを右クリックしてビルドしておきましょう。
(AWS Toolkit の動きが怪しくて、保存済みのファイルだとビルドしてデプロイされ、保存してないとビルドされないって動作がありますよね?)
「LambdaDemo.Lambda」プロジェクトを右クリック > publish to AWS Lambda...
をクリックします。
デプロイのための設定画面が表示されます。アカウントを選択し(前述の作業をしていれば表示されます)、Regionも作りたいリージョンを選びましょう(私は東京を選んでます)。
FunctionNameは、既存の Lambda を選ぶこともできますし、新規に入力すると、新しく Lambda を作成してくれます。今回は、「lambdaDemo1」という 関数名で作ります。その他の項目も確認して、Next
をクリックします。
後は、Role Nameを指定します。この画面で、Memoryの割り当てやTimeout時間、環境変数を設定することもできます。
Upload
をクリックするとデプロイが開始します。
デプロイ時、わけわからないエラーがでることが(私の場合、仕事の時に)多々ありましたが、プログラムはおかしくない前提で話すと、なんどかデプロイ連打すれば正常にデプロイできました。
Web から動作確認
デプロイが完了すると、VS2017からでもテスト実行できる画面が表示されて便利です。
が、今回は、AWS のマネジメントコンソールから動作確認してみましょう。今作った関数「lambdaDemo1」を開きましょう。関数名「lambdaDemo1」の画面を適当に開いて、 アクション
> テストイベントの設定
をクリックします。
「Hello World」のテンプレートがデフォルトで表示されます。想定したJSONのフォーマットの key1
があって丁度良いので、このまま 保存してテスト
をクリックしましょう。
正常に動作すると、こんな画面になります。ログをクリックしてみましょう。
ログストリームの一覧が出てきますので、今実行したらしきログを開いてみると....
無事に動作してます。
今回はここまでで、次回に続きますー♪