今回は AWS のサーバーレスという分類に属する Lambda を Visual Studio 2019 C# で構成する方法について覚え書きします。AWS Toolkit をインストールすることで Visual Studio 上で作成した C# のコードを Lambda 関数としてデプロイすることが可能です。
前提条件
・Windows10 Pro 64Bit 2004
・Visual Studio 2019 Community v16.9.4
・C# .NET Core 3.1
・AWS で開発用のアカウントを取得して、決済情報を登録していること
1.Lambda の特徴
前提として AWS Lambda の特徴についておさらいしておきましょう。実行可能な条件がかなり厳しいために使用できる場面が限られてきますので、注意が必要です。
・1か月あたりの従量課金制です。
・1か月あたり100万リクエストまでの無料枠があります。
・1つの関数の処理実行時間は最大15分まで
・同時実行数1000まで処理が可能。
・同時実行数は事前申請で拡張が可能。
・同時実行数を超えた場合はスロットリング(制限)されます。
・初回実行時はコールドスタートのため、2~3秒ぐらい待ちます。
(※初回実行時は内部的にDockerコンテナを立ち上げる時間が必要なため、コールドスタートとなる。ウォームアップ状態(ホットスタンバイ)として待機するように設定するとDockerコンテナの使用時間が料金に加算されてしまうため、Fargateよりも高くなってしまうケースがあるなど懸念点は多い。)
上記から使用用途としては、スモールスタート的なアプリに適しており、大規模なシステムや実行速度を求める要件があるシステムでは使用が難しい条件ですね。また、処理時間の関係上、夜間バッチに使用することも難しいです。
Lambda関数を実装するにしても非同期処理でリトライ機能を持たせて、UIにはスピナーを表示してユーザーに処理中であることを通知することが望ましいでしょう。
2.AWS Toolkit のインストール
以下の AWS のサイトから Visual Studio 2019 用の AWS Toolkit をダウンロードしてインストールします。
https://aws.amazon.com/jp/visualstudio/
※アドオンであるため、Visual Studio が起動しているとインストールが途中で進まなくなります。

3.Visual Studio 上での開発方法
Visual Studio を起動して、新しいプロジェクトの作成または追加をします。
AWS Lambda Project(.NET Core - C#)を選択して、次に進みます。

プロジェクトのディレクトリや名称を決定して次に進むと、 Lambda で使用する開発テンプレートの選択画面になります。ここでは Empty Function を選択します。デフォルトで .NET Core 3.1 の開発テンプレートになっています。

Finish ボタンを押下すると、Lambda用のプロジェクトが VS のソリューションエクスプローラーに表示され、開発ができるようになります。
4.C# .NET Core の構成方法
初期の Lambda のプロジェクト内に Function.cs が作成されていますが、これを以下のように書き換えます。(あくまでサンプルです。他にも構成方法があります。)
AWSLambdaSampleApp.Function.cs
using System.Collections.Generic;
using Amazon.Lambda.Core;
using Newtonsoft.Json;
using System.Net;
// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace AWSLambdaSampleApp
{
/// <summary>
/// Lambdaのリクエスト情報を保持する
/// </summary>
public class LambdaRequest
{
[JsonProperty(PropertyName = "body")]
public string body { get; set; }
}
/// <summary>
/// Lambdaのレスポンス情報を保持する
/// Lambdaプロキシ統合を使用する場合は、
/// 以下の 4つのプロパティの名称が異なっていたり、大文字小文字の違いや、
/// 綴りが間違っていると502の内部エラーになってしまいますので注意が必要です。
/// </summary>
public class LambdaResponse
{
[JsonProperty(PropertyName = "isBase64Encoded")]
public bool isBase64Encoded { get; set; }
[JsonProperty(PropertyName = "statusCode")]
public HttpStatusCode statusCode { get; set; }
[JsonProperty(PropertyName = "headers")]
public Dictionary<string, string> headers { get; set; }
[JsonProperty(PropertyName = "body")]
public string body { get; set; }
}
/// <summary>
/// Lambdaに送信したい情報のモデルクラスです。任意の構成が可能です。
/// </summary>
public class RequestParam
{
[JsonProperty(PropertyName = "value1")]
public int value1 { get; set; }
[JsonProperty(PropertyName = "value2")]
public int value2 { get; set; }
}
/// <summary>
/// Lambdaから受信したい情報のモデルクラスです。任意の構成が可能です。
/// </summary>
public class ResponseParam
{
[JsonProperty(PropertyName = "result")]
public int result { get; set; }
}
/// <summary>
/// Lambda関数
/// </summary>
public class Function
{
/// <summary>
/// Lambdaのエントリポイント
/// </summary>
/// <param name="input">リクエスト情報</param>
/// <param name="context"></param>
/// <returns></returns>
public LambdaResponse FunctionHandler(LambdaRequest input, ILambdaContext context)
{
var data = JsonConvert.DeserializeObject<RequestParam>(input.body);
var header = new Dictionary<string, string>()
{
{"x-custom-header" , "my custom header value" }
};
return new LambdaResponse
{
//Lambdaプロキシ統合を使用する場合は、
//レスポンスの形式はこの形式でないとHTTPステータスコード502の内部エラー(Internal Sever Error)で返ってきてしまいます。
isBase64Encoded = false,
statusCode = HttpStatusCode.OK,
headers = header,
body = JsonConvert.SerializeObject(
new ResponseParam
{
result = data.value1 * data.value2 * 2 //処理結果を示す簡単な計算式です(任意です)
})
};
}
}
}

5.Lambda へのデプロイ方法
C# での開発が完了したら、初回のみ AWS へデプロイするためのアクセスキーを埋め込みます。VS メニューの 表示 > AWS Explorer を選択し、アカウントを追加します。

以下の画面に アクセスキーとシークレットアクセスキーを入力します。Region は Lambda を実行するリージョンを指定します。

アクセスキーがない場合は、AWS のコンソール上で アカウント名 > マイセキュリティ資格情報 と進み、アクセスキーを発行します。

アカウントが登録できたら、VS の Lambda プロジェクトを右クリックして、「Publish To AWS Lambda...」を選択します。

次に AWS Lambda で表示するための項目を入力します。
項目名 | 入力する値について |
Package Type |
Zipを選択します。DLLなどのファイルをまとめて圧縮してAWSに送信します。 |
Lambda Runtime |
C#プロジェクトで使用している対象のフレームワークを設定します。 |
Configration |
Release/Debug を選択します。Debug にしても AWS にアタッチができないため、コードのデバッグはできませんでした。 |
Function Name |
AWS Lambda の画面で表示する関数名 |
Assembly |
プロジェクトのプロパティで設定しているアセンブリ名。デフォルトはプロジェクト名称が入っています。 |
Type |
プロジェクト名.Function |
Method |
Function.cs内のエントリポイントの関数名 |

次に AWS で Lambda のフルアクセス権限をもつロールを選択します。ロールを作成していない場合は、事前に AWS IAM のサイトで作成します。メモリはサンプルの為の構成なので、最低の 128MB を選択しました。実行するプログラムに合わせて変更する必要があります。Uploadボタンを押下すると AWS に Lambda 関数がデプロイされます。

※SQSのエラーが表示されているかもしれませんが、SQSは使用しないため、無視して進みます。
6.Lambda の実行方法
(1) VS 上での実行方法
Lambda をデプロイしたら、VS 上に Test Function の画面が表示されます。
Example Request のボディ欄に以下のJSONを入力して、Invoke ボタンを押下すると、右側の Response 欄に結果が表示されます。
{
"body": "{\"value1\": 3, \"value2\": 4}"
}
※API Gateway を経由しない場合は、プロキシ統合を使用するしないに関わらず上記のJSONフォーマットになります。

(2)AWS Lambda コンソール上での確認方法
AWS Lambda > 関数 > {Lambda関数名} > テスト からテストが行えます。
同じくBodyにJSONを入力して、テストボタンを押下すると、結果が詳細の中に表示されます。

(3)API Gateway を構成して、インターネット越しにアクセスする方法
これは本番環境と同じ構成となります。上記の AWS Lambda 画面に「トリガーを追加」ボタンがありますので、押下します。
以下の構成でAPI Gateway を作成します。
項目名 | 入力する値について |
追加するトリガー |
API Gateway |
API |
APIを作成する |
APIタイプ |
REST API |
セキュリティ |
オープン |
追加の設定 |
なし(デフォルトのまま) |

API Gateway が追加できたら、まずは AWS のコンソールから API Gateway のテストを行います。
Lambda > 関数 > 関数名 > トリガー > API Gateway > 統合リクエスト > テスト と進みます。
以下のように メソッドとBodyを入力してテストボタンから実行すると結果が得られます。正常に返ってくる状態であれば、API Gateway をデプロイします。
※API Gateway でプロキシ統合を使用する場合は以下のようなリクエストになります。
{
"value1": 3, "value2": 4
}

※上記イメージ画像ではプロキシ統合を使用しないリクエスト・レスポンスになっています。
そして、完全に外部からアクセスするには、API Gateway の URL を確認する必要があります。API Gateway を選択すると詳細から URL を取得できますので、Chrome のアドオンである、Advanced REST clientAdvanced REST client などのツールを使用して POST のテストを行います。

※上記イメージ画像ではプロキシ統合を使用しないリクエスト・レスポンスになっています。
以上で、インターネット越しのアクセスが正常に確認でき、Visual Studio 2019 C# .NET Core で作成したプロジェクトを AWS Lambda で実行できたことが確認できました。
その他、注意点としましては、別プロジェクトの共通処理があるために、プロジェクト参照などしていると、そのままでは正しくデプロイできず、プロジェクト参照を「ローカルにコピー」の設定にするとデプロイができる点や、プロキシ統合を使用するしないでリクエストレスポンスの形式が若干異なる点や、API Gateway の設定手順の違いで HTTPステータスコード 502 Internal Server Error になる場合があるなど、注意が必要な点がありました。
- 関連記事
-