らくがきちょう

なんとなく ~所属組織/団体とは無関係であり、個人の見解です~

Visual Studio 2019 の C# で AWS Lambda + API Gateway を書く

Visual Studio 2019 上で直接、AWS Lambda 開発を行うことが出来ます。 今回は Visual Studio 2019 上で AWS Lambda 開発を行い、更にそれを API Gateway で公開する手順をメモしておきます。

必要な項目

  1. プログラマブルアクセスが可能な IAM ユーザ (アクセスキー&シークレットキー情報)
  2. AWS アカウント ID

Step.1

予め、AWS Toolkit for Visual Studio をインストールしておきます。

f:id:sig9:20191229014033p:plain:w800

Step.2

Visual Studio 2019 を起動し、新しいプロジェクトの作成 をクリックして次へ進みます。

f:id:sig9:20191229002914p:plain:w800

Step.3

画面上部から AWS を選択し、表示されたテンプレートから AWS Lambda Project (.NET Core - C#) を選択し、次へ をクリックして次へ進みます。

f:id:sig9:20191229002917p:plain:w800

Step.4

任意のプロジェクト名を入力したら 作成 をクリックして次へ進みます。

f:id:sig9:20191229002920p:plain:w800

Step.5

ブループリントを選択します。 今回は最小のサンプルを作成するので Empty Function を選択し、Finish をクリックして次へ進みます。

f:id:sig9:20191229002925p:plain:w800

Step.6

ソリューションが表示されます。

f:id:sig9:20191229002928p:plain:w800

初期状態の Function.cs

初期状態の Function.cs はおそらく以下のようになっているはずです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

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.Json.JsonSerializer))]

namespace AwsSample
{
    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();
        }
    }
}

修正後の Function.cs

Function.cs の内容を以下のように変更します。

using Amazon.Lambda.Core;
using Newtonsoft.Json;
using System.Collections.Generic;
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.Json.JsonSerializer))]

namespace AwsSample
{
    public class LambdaRequest
    {
        [JsonProperty(PropertyName = "body")]
        public string Body { get; set; }
    }

    public class LambdaResponse
    {
        [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; }
    }

    public class RequestParam
    {
        [JsonProperty(PropertyName = "a")]
        public int A { get; set; }

        [JsonProperty(PropertyName = "b")]
        public int B { get; set; }
    }

    public class ResponseParam
    {
        [JsonProperty(PropertyName = "result")]
        public int Result { get; set; }
    }

    public class Function
    {
        public LambdaResponse FunctionHandler(LambdaRequest input, ILambdaContext context)
        {
            var data = JsonConvert.DeserializeObject<RequestParam>(input.Body);
            return new LambdaResponse
            {
                StatusCode = HttpStatusCode.OK,
                Headers = null,
                Body = JsonConvert.SerializeObject(
                    new ResponseParam
                    { Result = data.A * data.B })
            };
        }
    }
}

Step.7

表示AWS Explorer をクリックして次へ進みます。

f:id:sig9:20191229002931p:plain:w800

Step.8

AWS Explorer が表示されます。 Profile の右横にある 人形にプラスマーク のアイコンをクリックして次へ進みます。

f:id:sig9:20191229003649p:plain:w800

Step.9

次の手順で AWS アカウント ID が必要になる為、予め確認しておきます。 AWS 管理コンソールへログインし、マイアカウントホーム から アカウント ID を確認することが出来ます。 確認した アカウント ID は次の手順に備えて控えておきます。

f:id:sig9:20191229003653p:plain:w800

Step.10

以下に従って値を入力したら OK をクリックして次へ進みます。

項目
Profile Name 任意の名前
Access Key ID プログラマブルアクセス可能な IAM ユーザのアクセスキー
Secret Access Key プログラマブルアクセス可能な IAM ユーザのシークレットキー
Account Number AWS アカウント ID

f:id:sig9:20191229003657p:plain:w800

Step.11

AWS ExplorerProfile にはひとつ前の手順で作成したプロファイル名が表示されているはずです。 Region は今回、Asia Pacific (Tokyo) を選択しました。

f:id:sig9:20191229003701p:plain:w800

Step.12

以降の手順でソリューションエクスプローラを利用する為、もしソリューションエクスプローラが表示されていない場合は 表示ソリューションエクスプローラ をクリックし、ソリューションエクスプローラを表示しておきます。

f:id:sig9:20191229004729p:plain:w800

Step.13

ソリューション名を右クリックし、表示されたコンテキストメニューから Publish to AWS Lambda をクリックして次へ進みます。

f:id:sig9:20191229004732p:plain:w800

Step.14

Account profile to useRegion が意図したものになっているか、確認します。 Function Name には AWS Lambda 上に作成したい関数名を入力し、Next をクリックして次へ進みます。

f:id:sig9:20191229004735p:plain:w800

Step.15

Role Name からは必要になる IAM Role を選択します。 今回はサンプルなので AWSLambdaFullAccess を選択しました。 MemoryTimeout は必要要件に応じて調整すべき項目ですが、今回は Memory:128, Timeout:10 としました。 Upload をクリックして次へ進みます。

f:id:sig9:20191229004738p:plain:w800

Step.16

AWS Lambda へ関数がアップロードされるので、完了するまでしばらく待機します。

f:id:sig9:20191229004742p:plain:w800

Step.17

関数のアップロードが完了すると Test Function が表示されるはずです。 この画面から実際に Lambda を実行することが可能です。 Example Requests へ以下を入力し、Invoke をクリックして次へ進みます。

{
  "body": "{\"A\": 3, \"B\": 4}"
}

f:id:sig9:20191229004745p:plain:w800

Step.18

結果が表示されます。 Response の中身が意図したものになっていることを確認します。

f:id:sig9:20191229004749p:plain:w800

Step.19

AWS 管理コンソールから Lambda を選択すると、アップロードした関数が表示されていることが分かります。 この関数名をクリックして次へ進みます。

f:id:sig9:20191229005153p:plain:w800

Step.20

この関数の実行トリガーに APi Gateway を追加する為に トリガーの追加 をクリックして次へ進みます。

f:id:sig9:20191229005157p:plain:w800

Step.21

トリガーの設定 から API Gateway を選択します。

f:id:sig9:20191229005201p:plain:w800

Step.22

新規 API の作成 を選択し、テンプレートは REST API を選択します。 現時点でベータリリースされている HTTP API を使っても良いのですが、HTTP API として APi Gateway を利用した場合に「IP アドレス制限」等を設定する方法が分からなかった為、今回は REST API を選択しました (今回は IP アドレス制限の設定を行いませんが…)。 セキュリティは オープン にしておきます。 追加 をクリックして次へ進みます。

f:id:sig9:20191229010317p:plain:w800

Step.23

これでトリガーに API Gateway が追加されました。 URL は関数の表示画面最下部に表示されているので控えておきます。

f:id:sig9:20191229010321p:plain:w800

Step.24

(必須ではありませんが) AWS 管理コンソールから API Gateway を選択すると、Lambda のトリガーとして作成された API が存在することを確認出来ます。

f:id:sig9:20191229010324p:plain:w800

Step.25

最後に、実際にクライアントから API Gateway へアクセスし、意図したレスポンスがあることを確認します。 今回は Postman から必要なパラメータを指定して API Gateway へアクセスし、意図したレスポンスが返ってくることを確認しました。

f:id:sig9:20191229010328p:plain:w800