[AWS.2] Lambdaサンプル(C#) の作成とデプロイ

## 1. 概要
本記事では、.NET6(C#) で Lambda関数プロジェクトの作成方法 および AWS へのデプロイ方法について説明します。

:::note warn
同様の記事はネット上に溢れており、開発ツールのバージョンアップも頻繁に行われています。
本記事の内容もあっという間に陳腐化すると思われますので、ご注意ください。
:::

#### サンプル仕様
次の仕様でサンプルを作成します。
　a. 単一の文字列を入力値として受け取る。
　b. 入力値に「年月日」を付加した文字列を作成し、関数の返却値とする。

このサンプルは、プロジェクトテンプレート「lambda.EmptyFuction」を使って作成します。

#### 本記事を作成する際に参考にしたサイト
初級：AWS Lambda + .NET C# の最初の一歩
https://qiita.com/nanananamememe/items/8c57b17e5f7f60b768d4

.NET Core Serverless WebAppをMacからAWSへデプロイ
https://qiita.com/ryohei0109_develop/items/22782f0d9d20bce93f43

Visual Studioの無いWindows環境でC# Lambdaの開発環境を整える
https://dev.classmethod.jp/articles/how-to-setup-csharp-lambda-development-env-with-vscode/


## 2. プロジェクトの新規作成
新たなプロジェクトを作成するソリューションを作成します。
（既存のソリューションをそのまま使っても問題ありません）

### (1) Lambda関数プロジェクトの作成
Lambda 関数プロジェクトを作成する任意のフォルダへ移動し、「dotnet new」コマンドを実行します。
このコマンドを使うと、指定したテンプレートに基づいて新しいプロジェクトを作成することができます。
https://docs.microsoft.com/ja-jp/dotnet/core/tools/dotnet-new

```
$ dotnet new lambda.EmptyFunction --name {プロジェクト名} --profile {プロファイル名} --region {リージョン名}
```
|オプション|説明|
|:------|:--|
|--name {プロジェクト名}|新たに作成するプロジェクトの名前。<br/>AWS へデプロイする関数名と同じ名前にしておく。|
|--profile {プロファイル名}|使用するプロファイルの名前。<br/>明示的にプロファイルを作成していなければ "default" と指定する。|
|--region {リージョン名}|関数が動作する際のリージョンを指定する。<br/>Asia Pacific (Tokyo) の場合は "ap-northeast-1" と指定する。|

　
以下はコマンドの実行例です。
```
$ dotnet new lambda.EmptyFunction --name EchoSample --profile default --region ap-northeast-1
テンプレート "Lambda Empty Function" が正常に作成されました。
```

　
コマンドが成功すると「src」と「test」というフォルダが作成されます。
<img width="70%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/7feceede-982a-a5e9-2280-bbf42d236f2b.png" />
### (2) ソリューションへの取り込み
VisualStudio でソリューションファイルを開き、作成したプロジェクトを取り込みます。
ソリューションへの [追加]-[既存のプロジェクト]　で、作成された「src」フォルダ下のプロジェクトファイル（拡張子「.csproj」）を指定してください。
このサンプルでは、「EchoSample.csproj」を指定します。

無事に取り込まれたプロジェクトを展開すると、下図のように「フレームワーク」と「NuGet」へ必須ソフトウェアがすでに登録されています。
このサンプルでは、他に追加する必要はありません。
<img width="70%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/f512fa00-2b88-eb60-8bf7-7b214750835c.png" />
### (3) aws-lambda-tools-defaults.json の確認
aws-lambda-tools-defaults.json を開いて中身を確認します。
```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",
  "function-runtime": "dotnet6",
  "function-memory-size": 256,
  "function-timeout": 30,
  "function-handler": "EchoSample::EchoSample.Function::FunctionHandler"
}
```
「profile」と「region」には同名のオプションで指定した値が、「function-handler」には「--name」オプションで指定した名前から生成したハンドラ名が記述されています。

## 3. ロールの作成
Lambda関数には実行用のIAMロールを指定する必要があります。
このロールには**Lambda関数が取り扱うリソースへのアクセス権限**を示す「ポリシー」を登録します。

AWS Lambda 実行ロール
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-intro-execution-role.html

上記サイトの「IAM コンソールでの実行ロールの作成」に記述されている手順に従い、下記のポリシーを登録した新しい実行用IAMロールを用意してください。
ロール名は任意の名称で構いません。（例. "EchoSample-role"）
* AWSXRayDaemonWriteAccess
* AWSLambdaBasicExecutionRole

## 4. プログラムコードの確認
生成された Lambda関数 プログラムソース（Function.cs）を確認してみます。
```C#
using Amazon.Lambda.Core;

// 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 EchoSample;

public class Function
{
    /// <summary>
    /// A simple function that takes a string and does a ToUpper
    /// </summary>
    /// <param name="input"></param>
    /// <param name="context"></param>
    /// <returns></returns>
    public string FunctionHandler(string input, ILambdaContext context)
    {
        return input.ToUpper();
    }
}
```
引数で受け取った文字列を「大文字」に変換して返却する、という非常に単純なサンプルです。
サンプル仕様 b. に基づき、関数の中身を下記のように修正します。

```C#
    public string FunctionHandler(string input, ILambdaContext context)
    {
        string dt = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff");
        return String.Format($"[{dt}] echo: {input}");
    }
```

:::note info
VisualStudio で最初に Function.cs を開いた際、```using Amazon.Lambda.Core;``` の行に 赤波下線 が表示されました。
同様の事象が発生した場合は NuGet パッケージの「復元」を試みると解消されるかもしれません。

私の場合は たまたま VisualStudio の更新とタイミングが被り、更新＆再起動を実施した後にソリューションを開くと NuGet パッケージの復元が実施されました。
その結果、赤波下線 表示が解消されました。
:::

## 5. AWS へのデプロイ
プロジェクトファイル（EchoSample.csproj）が存在するフォルダへ移動後、次のコマンドを続けて実行すると、パッケージ作成 および AWS へのデプロイが行われます。

```
dotnet restore
dotnet lambda deploy-function {関数名} --function-role {IAM実行ロール名} --profile {プロファイル名}
```

|オプション|説明|
|:------|:--|
|{関数名}|Lambda 関数の名前。|
|--function-role {IAM実行ロール名}|作成済みの 実行用IAMロール名。|
|--profile {プロファイル名}|使用するプロファイルの名前。<br/>省略した場合は default を指定したとみなされる。|

　
以下は本サンプルでの実行例。
```
$ dotnet restore
  復元対象のプロジェクトを決定しています...
  復元対象のすべてのプロジェクトは最新です。
$ dotnet lambda deploy-function EchoSample --function-role EchoSample-role --profile default
Amazon Lambda Tools for .NET Core applications (5.4.4)
Project Home: https://github.com/aws/aws-extensions-for-dotnet-cli, https://github.com/aws/aws-lambda-dotnet
	
Executing publish command
... invoking 'dotnet publish', working folder '/Users/*****/VisualStudioProjects/AwsSamples/EchoSample/src/EchoSample/bin/Release/net6.0/publish'
... dotnet publish --output "/Users/*****/VisualStudioProjects/AwsSamples/EchoSample/src/EchoSample/bin/Release/net6.0/publish" --configuration "Release" --framework "net6.0" /p:GenerateRuntimeConfigurationFiles=true --runtime linux-x64 --self-contained false 
... publish: .NET 向け Microsoft (R) Build Engine バージョン 17.2.0+41abc5629
... publish: Copyright (C) Microsoft Corporation.All rights reserved.
... publish:   復元対象のプロジェクトを決定しています...
... publish:   /Users/*****/VisualStudioProjects/AwsSamples/EchoSample/src/EchoSample/EchoSample.csproj を復元しました (9.7 sec)。
... publish:   EchoSample -> /Users/*****/VisualStudioProjects/AwsSamples/EchoSample/src/EchoSample/bin/Release/net6.0/linux-x64/EchoSample.dll
... publish:   EchoSample -> /Users/*****/VisualStudioProjects/AwsSamples/EchoSample/src/EchoSample/bin/Release/net6.0/publish/
Changed permissions on published file (chmod +rx EchoSample.dll).
Changed permissions on published file (chmod +rx EchoSample.deps.json).
Changed permissions on published file (chmod +rx EchoSample.pdb).
Changed permissions on published file (chmod +rx Amazon.Lambda.Serialization.SystemTextJson.dll).
Changed permissions on published file (chmod +rx Amazon.Lambda.Core.dll).
Changed permissions on published file (chmod +rx EchoSample.runtimeconfig.json).
Zipping publish folder /Users/*****/VisualStudioProjects/AwsSamples/EchoSample/src/EchoSample/bin/Release/net6.0/publish to /Users/*****/VisualStudioProjects/AwsSamples/EchoSample/src/EchoSample/bin/Release/net6.0/EchoSample.zip
... zipping:   adding: EchoSample.dll (deflated 58%)
... zipping:   adding: EchoSample.deps.json (deflated 68%)
... zipping:   adding: EchoSample.pdb (deflated 42%)
... zipping:   adding: Amazon.Lambda.Serialization.SystemTextJson.dll (deflated 50%)
... zipping:   adding: Amazon.Lambda.Core.dll (deflated 56%)
... zipping:   adding: EchoSample.runtimeconfig.json (deflated 32%)
Created publish archive (/Users/*****/VisualStudioProjects/AwsSamples/EchoSample/src/EchoSample/bin/Release/net6.0/EchoSample.zip).
Creating new Lambda function EchoSample
New Lambda function created
$ 
```

コマンドを実行するとソースがビルドされ、デプロイ用のパッケージ ZIPファイルが作成されます。
その後、AWS上にデプロイされて Lambda 関数として登録されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/e9c0dfbd-3a58-bb49-ec3c-624983bbf516.png)

## 6. AWS上でのテスト実行
EchoSample 関数を開き、「テスト」タブからテストを実行してみます。
「新しいイベントを作成」を選択してから **イベント名**　を入力してください。
（例. EchoSampleTest）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/d8b7c480-d329-dd18-c8c6-f2942ce74cdf.png)

画面下部の「イベントJSON」の記述は、下記の形に変更してください。
これはサンプルプログラムが単一の文字列しか引数で受け取れないためです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/84594166-71c4-7843-02b1-12f66e3536a2.png)
変更後は、忘れずに [保存]ボタンをクリックしてください。 
[テスト]ボタンをクリックすると、実行結果が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/41b5badc-7299-d6c3-f128-12e475f5307e.png)

## 7. 終わりに
自動作成されたサンプルソースをほとんどそのまま使用しましたが、C# でLambda 関数を作成してデプロイ＆テスト するまでの流れを簡単に説明してきました。
一連の操作を繰り返し実施して、基本的な作業の流れを身につけることをお勧めします。

:::note info
MacOS の VisualStudio で Lambda 関数を手掛ける人は少ないかもしれません。
ただ、説明してきたコマンド操作などは Windows 上の Visual Studio Code での作業に通じるところもあり、参考情報の一つにはなると思います。
:::