AWS Lambda用に.NET Coreで書いたAPIサーバをDockerでローカルでも実行させてみた

# AWS Lambda用に.NET Coreで書いたAPIサーバをDockerでローカルでも実行させてみた

## はじめに

.NET CoreもC#も未経験の筆者が、AWS上で.NET Core Webアプリケーションを作成する必要に駆られたので、お試しでデプロイとローカルデバグ用の開発環境を構築してみました。
備忘録を兼ねてメモを残します (テック記事は人のためならず)。

これはアカンとか、何書いているのﾌﾟﾌﾟみたいなことがあればご指摘いただけますと、たいへんありがたいです。

## Introduction

今回の要件は以下の通りです。

* 開発は.NET Core (この記事執筆時点では2.1)
* 開発言語はC#
* 動作環境はAWS Serverless Architecture (APIGateway + Lambda + DynamoDB etc.)

なお、開発環境としてはVisual Studio 2019を使用しています。
なお、機能として、"ASP.NETとWeb開発"と".NET Coreクロスプラットフォームの開発"をインストールしています。


## 準備

プロジェクトを開始する前に、以下の準備を行います。

### AWS toolkit for Visual Studio 2017 and 2019

拡張機能としてVisual Studio Marketplaceから、"AWS toolkit for Visual Studio 2017 and 2019"をインストールします。

> "拡張機能"メニュー → "拡張機能の管理" → "AWS toolkit for Visual Studio 2017 and 2019"を検索してインストール

### AWS Explorer

Visual StudioでAWS Explorerを起動し、今回の環境を実行するAWSへのアクセス情報Profileを作成します。

> "表示"メニュー → "AWS Explorer"　→ "New Account Profile"ボタン

Profileの各項目は以下のように入力します。

<dl>
<dt>Profile Name</dt>
<dd>default</dd>
<dt>Storage Location</dt>
<dd>Shared Credentials File</dd>
<dt>Access Key ID</dt>
<dd>今回の作業に必要な権限を持つユーザーのAccess Key</dd>
<dt>Secret Access Key</dt>
<dd>同じくユーザーのSecret Access Key</dd>
<dt>Account Number</dt>
<dd>AWSアカウントID</dd>
</dl>

### aws configure

Power Shellなどを起動し、aws configureコマンドを実行して、AWSへの接続情報を入力します。

```
PS C:\Users\hogehoge> aws configure
```

<dl>
<dt>AWS Access Key ID</dt>
<dd>上記のprofileと同じAccess Key</dd>
<dt>AWS Secret Access Key</dt>
<dd>上記のprofileと同じSecret Access Key</dd>
<dt>Default region name</dt>
<dd>ap-northeast-1</dd>
<dt>Default output format</dt>
<dd>json</dd>
</dl>


### Docker Desktop

dockerを使用しますので、Docker Desktopをインストールします。

Docker Desktopを実行する場合は、コントロールパネルで、Windowsの機能として"Hyper-V"と"Windows ハイパーバイザープラットフォーム"を有効にする必要があります。なお、"Hyper-V"を使用するため"VirtualBox"アプリケーションは使用できなくなってしまいます(残念)。


### REST API用ツール

テスト用に、REST APIにアクセスするためのツールやブラウザのextensionがあると便利です。


## ソリューション作成

Visual Studioを使って、冒頭の要件に合うプロジェクトを作っていきます。
今回は、プロジェクトテンプレート"AWS Serverless Application with Tests (.NET Core - C#)"内の"Blog API using DynamoDB"をテンプレートとして使用します。

また、ローカル環境上でDockerコンテナとして動作するASP.NET Coreアプリケーションも同時に作成します。これにより、AWS環境がなくてもデバグが可能になります(今回はSAM(Serverless Application Model)のlocal環境機能は使用しません)。

![structure.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120318/b94adf6e-615a-c641-53e0-857c49f9adba.png)


### ソリューション(Serverless Applicationプロジェクト)新規作成

Visual Studioを起動し、新しいプロジェクトの作成ダイアログを起動します。

> "ファイル"メニュー → "新規作成" → "プロジェクト"

テンプレートとして、"AWS Serverless Application with Tests (.NET Core - C#)"を選択します。
なお、今回は、プロジェクト名とソリューション名を"Hoge"にし、Blueprintとして"Blog API using DynamoDB"を選択します。

すると、ソリューションには、Serverless Application用プロジェクト"Hoge"と、そのテスト用プロジェクト"Hoge.Tests"が作成されているはずです。


### 共通プロジェクト

.NET Coreを使用したServerless Applicationと、ローカルのDockerで動作させるためのASP.NET Coreアプリケーションの両方で共通で使用するたの.NET Core Library用のプロジェクトを作成します。

再び、新規プロジェクトを作成しますが、今度は、プロジェクトテンプレートとして"クラス ライブラリ(.NET Core)"を選択します。

> ソリューションエクスプローラで、ソリューション"Hoge"を右クリック → "追加" → "新しいプロジェクト"

プロジェクト名を"HogeLib"にして、プロジェクトを作成します。
プロジェクトを作成したら、対象のフレームワークを".NET Core 2.1"に変更します。

> ソリューションエクスプローラで、"HogeLib"プロジェクトを右クリック → "プロパティ"　→ "対象のフレームワーク"を変更


### 参照関係の修正

"Hoge"プロジェクトから"HogeLib"を参照できるように、設定を追加します。

> ソリューションエクスプローラで、"Hoge"を右クリック → "追加" → "参照"

参照するプロジェクトとして"HogeLib"のチェックボックスを有効にしてから、"OK"を押します。


### 共通コードの作成

今回の共通コードの作成は、HogeプロジェクトのBlog.csモデルクラスを、HogeLibプロジェクトに移動させるだけにします。 
本来であれば、ロジックも移動させるのですが、説明と修正を簡単にするために、今回はモデルクラスのみの移動とします。

モデルクラスの移動は以下のように行いました (JetBrains社のRiderがあれば簡単なんですが・・・)。

* HogeLib/Class1.csはもう必要無いので削除
* HogeLibプロジェクト下に新しいフォルダー"Models"を作成
* Hoge/Blog.csをHogeLib/Modelsフォルダの下にMove
* HogeLib/Models/Blog.csのnamespaceを"Hoge"から"HogeLib.Models"に変更
* Hoge/Functions.csに"using HogeLib.Models"を追加
* Hoge.Tests/FunctionTest.csに"using HogeLib.Models"を追加


### Regionの変更

"Blog API using DynamoDB"BluePrintで生成されたコードはそのままではRegionの関係で動かないので、コードを修正します。

```Hoge\Functions.cs
//this.DDBContext = new DynamoDBContext(new AmazonDynamoDBClient(), config);
this.DDBContext = new DynamoDBContext(new AmazonDynamoDBClient(RegionEndpoint.APNortheast1), config);
```

```Hoge.Tests\FunctionTest.cs
//this.DDBClient = new AmazonDynamoDBClient(RegionEndpoint.USWest2);
this.DDBClient = new AmazonDynamoDBClient(RegionEndpoint.APNortheast1);
```

### Publish

これで、Serverless Application用の修正は完了しましたので、ひとまずAWSにPublishします。

> ソリューションエクスプローラで、"Hoge"を右クリック → "Publish to AWS Lambda..."

ダイアログの各項目は、以下のように設定します。
なお、Publishに使用するS3バケットは、予めAWSコンソールで作成しておくか、ダイアログ上の"New..."ボタンで作成します。

<dl>
<dt>Account profile to use</dt>
<dd>default</dd>
<dt>Region</dt>
<dd>Asia Pacific (Tokyo)</dd>
<dt>Build Settings Configuration</dt>
<dd>Release</dd>
<dt>Framework</dt>
<dd>netcoreapp2.1</dd>
<dt>Stack Name</dt>
<dd>HogeStackFoo  (Fooは他の人と被らないようにするための適当な文字列。同一AWSアカウント内で衝突しないように)</dd>
<dt>S3 Bucket</dt>
<dd>hogestackfoo (Fooは他の人と被らないようにするための適当な文字列。なお上記のstackと同じである必要は無い。S3の命名規則に注意)</dd>
<dt>BlogTableName</dt>
<dd>Hoge-Blog-Foo (Fooは他の人と被らないようにするための適当な文字列。同一AWSアカウント内で衝突しないように)</dd>
<dt>ReadCapacity</dt>
<dd>1 (テスト用なので小さくてok)</dd>
<dt>ShouldCreateTable</dt>
<dd>true</dd>
<dt>WriteCapacity</dt>
<dd>1 (テスト用なので小さくてok)</dd>
</dl>

しばらくして、進行状況画面のStatusが"CREATE_IN_PROGRESS"から"CREATE_COMPLETE"になればPublish完了です。

なお、BlogTableNameを空にしておくと自動的に適当な名前をつけてくれるのですが、この後、Mock Lambda Test Toolでテーブル名を指定する必要があるので、ここでは明示的に名前を付けています。


### Mock Lambda Test Tool

AWS上のlambdaを直接デバグするためのツール"Mock Lambda Test Tool"用の設定を変更します。
変更箇所は、環境変数BlogTableに、一つ前のフェーズでBlogTableNameに指定した名前を設定したことです。

```Hoge\Properties\launchSettings.json
{
  "profiles": {
    "Mock Lambda Test Tool": {
      "commandName": "Executable",
      "commandLineArgs": "--port 5050",
      "workingDirectory": ".\\bin\\Debug\\netcoreapp2.1",
      "executablePath": "C:\\Users\\%USERNAME%\\.dotnet\\tools\\dotnet-lambda-test-tool-2.1.exe",
      "environmentVariables": {
        "BlogTable": "Hoge-Blog-Foo"
      }
    }
  }
}
```

### ASP.NET Core用プロジェクトの追加

ローカルのdocker環境で動作させるためのASP.NET Coreアプリケーション用のプロジェクトを追加します。

プロジェクトテンプレートとして"ASP.NET Core Web アプリケーション (C#)"を選択します。

> ソリューションエクスプローラで、ソリューション"Hoge"を右クリック → "追加" → "新しいプロジェクト"

プロジェクト名を"HogeWebApi"にします。その他の項目は以下のように設定します。

<dl>
<dt>SDK</dt>
<dd>.NET Core ASP.NET Core 2.1</dd>
<dt>プロジェクトテンプレート</dt>
<dd>API</dd>
<dt>認証</dt>
<dd>認証なし</dd>
<dt>HTTPS用の構成</dt>
<dd>無効(チェックを外す)</dd>
<dt>Dockerサポートを有効にする</dt>
<dd>有効(チェックする)</dd>
<dt>OS</dt>
<dd>Linux</dd>
</dl>

HogeWebApiからHogeLibを参照するようにします。

> ソリューションエクスプローラで、"HogeWebApi"を右クリック → "追加" → "参照"

参照するプロジェクトとして"HogeLib"のチェックボックスを有効にしてから、"OK"を押します。

次に、NuGetパッケージとしてAWSSDK.DynamoDBv2"をインストールします。

> ソリューションエクスプローラで、"HogeWebApi"を右クリック → "NuGetパッケージの管理" 

ASP.NET Core用のクロスプラットフォーム用WebサーバであるKestrel用にユーザーシークレットを作成する必要があるので、以下の操作でユーザーシックレット用のファイルを作成しておきます(中身は空のままでかまいません)。

> ソリューションエクスプローラで、"HogeWebApi"を右クリック → "ユーザーシークレットの管理" 

また、今回"wwwroot"ディレクトリは使わないので、削除してしまいます。


### docker-composeプロジェクトの追加

HogeWebApi ASP.NET Coreアプリケーションを動作させるためのオーケストレーション用プロジェクトとしてdocker-composeプロジェクトを手動で作成します。

エクスプローラ、PowerShellなどでHogeソリューションプロジェクトの直下に、"DockerCompose"というディレクトリを作成します。
そして、DockerCompose下に以下のVisual Studioのプロジェクトファイル(docker-compose.dcproj)をエディタ等で作成します。

```DockerCompose\docker-compose.dcproj
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" Sdk="Microsoft.Docker.Sdk">
  <PropertyGroup Label="Globals">
    <ProjectVersion>2.1</ProjectVersion>
    <DockerTargetOS>Linux</DockerTargetOS>
    <ProjectGuid>7530e2b9-bdab-44ab-87df-c6e6fc69b1b2</ProjectGuid>
    <DockerLaunchAction>None</DockerLaunchAction>
    <DockerServiceName>hogewebapi</DockerServiceName>
  </PropertyGroup>
</Project>
```

このプロジェクトファイルをソリューション"Hoge"に追加します。

> ソリューションエクスプローラで、ソリューション"Hoge"を右クリック → "追加" → "既存のプロジェクト"


### docker-composeプロジェクトの作成

まず、localで動作するdynamodbのDockerコンテナを作成します。
docker-composeプロジェクトに"localdynamodb"フォルダを作成します。

> ソリューションエクスプローラで、"docker-compose"を右クリック → "追加" → "新しいフォルダー" → "localdynamodb"にリネーム

localdynamodbフォルダの下に以下の二つのファイルをエディタ等で作成します。

```DockerCompose\localdynamodb\Dockerfile
FROM openjdk:8-jre

RUN mkdir /var/dynamodb_local
WORKDIR /var/dynamodb_local

RUN curl -fsSL https://s3-ap-northeast-1.amazonaws.com/dynamodb-local-tokyo/dynamodb_local_latest.tar.gz -o dynamodb.tar.gz \
  && tar xzf dynamodb.tar.gz \
  && rm dynamodb.tar.gz

COPY entrypoint.sh /bin/
RUN chmod 755 /bin/entrypoint.sh

ENTRYPOINT ["/bin/entrypoint.sh"]

EXPOSE 8000
```

```DockerCompose\localdynamodb\entrypoint.sh
#!/bin/sh

set -- java "$@"
set -- "$@" -Djava.library.path=/var/dynamodb_local/DynamoDBLocal_lib
set -- "$@" -jar /var/dynamodb_local/DynamoDBLocal.jar
set -- "$@" -sharedDb
set -- "$@" -dbPath /data
set -- "$@" -port 8000
exec "$@"
```

localdynamodbフォルダにこの二つのファイルを追加します。

> ソリューションエクスプローラで、フォルダ"localdynamodb"を右クリック → "追加" → "既存の項目" → 今回作成した"Dockerfile"と"entrypoint.sh"を指定

docker-compose用設定ファイルを作成します。
エディタ等でDockerComposeフォルダ下に以下のファイルを作成します。

```DockerCompose\docker-compose.yml
version: '3.4'

services:
  hogewebapi:
    image: ${DOCKER_REGISTRY-}hogewebapi
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_URLS=https://+:443;http://+:80
    build:
      context: ..
      dockerfile: HogeWebApi/Dockerfile
    container_name: hogewebapi
    ports:
      - "80"
      - "443"
    volumes:
      - ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro
      - ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro
    networks:
      - private_net

  localdynamodb:
    build:
      context: ./localdynamodb
    container_name: localdynamodb
    ports:
      - "8000"
    volumes:
      - dynamodb-data:/data
    networks:
      - private_net

networks:
  private_net:

volumes:
  dynamodb-data:
```
docker-compose.ymlファイルをdocker-composeプロジェクトに追加します。

> ソリューションエクスプローラで、"docker-compose"を右クリック → "追加" → "既存の項目" → 今回作成した"docker-compose.yml"を指定


### ASP.NET Coreアプリケーション用コントローラの作成

ASP.NET Coreアプリケーション用のコントローラを作成します。
コントローラの内容はAWS Serverlessアプリケーション用のBlog処理と同じ内容になります。

まず、テンプレートで作成されたサンプル用コントローラを削除します。

> HogeWebApi\Controllers\ValuesController.csを削除

次にBlog用コントローラを追加します。
コントローラーの種類は"APIコントローラー - 空"を選択します。コントローラー名は"BlogController"にします。

> ソリューションエクスプローラで、"HogeWebApi"のフォルダ"Controllers"を右クリック → "追加" → "コントローラー" → "APIコントローラー -空" 

BlogController.csの内容は以下のようになります。
なお、処理内容は、lambda用の.NET CORE アプリケーションのものとほぼ同様です (Hoge\Functions.cs)。

```HogeWebApi/Controllers/BlogController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

using HogeLib.Models;

using Amazon;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;
using Amazon.DynamoDBv2.Model;

namespace HogeWebApi.Controllers {
    [Route("blog")]
    [ApiController]
    public class BlogController : ControllerBase {
        IDynamoDBContext DDBContext {
            get; set;
        }

        /// <summary>
        /// Default constructor that Controller will invoke.
        /// </summary>
        public BlogController() {
            // Check to see if a table name was passed in through environment variables and if so 
            // add the table mapping.
            var tableName = "Hoge_Blog";
            AWSConfigsDynamoDB.Context.TypeMappings[typeof(Blog)] = new Amazon.Util.TypeMapping(typeof(Blog), tableName);

            AmazonDynamoDBConfig clientConfig = new AmazonDynamoDBConfig { ServiceURL = "http://localdynamodb:8000" };
            AmazonDynamoDBClient client = new AmazonDynamoDBClient("dummy", "dummy", clientConfig);

            try {
                // DynamoDB内にテーブルが無ければ新規作成する。もちろん本番用Controllerでこんなことをしてはいけない
                Task<CreateTableResponse> response = client.CreateTableAsync(
                    tableName,
                    new List<KeySchemaElement> {
                        new KeySchemaElement("Id", KeyType.HASH)
                    },
                     new List<AttributeDefinition> {
                        new AttributeDefinition("Id", ScalarAttributeType.S)
                    },
                    new ProvisionedThroughput {
                        ReadCapacityUnits = 1,
                        WriteCapacityUnits = 1
                    },
                    new System.Threading.CancellationToken()
                );
                response.Wait();
            } catch (Exception _) {
                // すでにあるならなにもしない
            }

            var config = new DynamoDBContextConfig { Conversion = DynamoDBEntryConversion.V2 };
            this.DDBContext = new DynamoDBContext(client, config);
        }

        // GET: blog
        [HttpGet]
        public async Task<IEnumerable<Blog>> GetAsync() {
            var search = this.DDBContext.ScanAsync<Blog>(null);
            var blogs = await search.GetNextSetAsync();

            return blogs;
        }

        // GET: blog/blogId
        [HttpGet("{blogId}", Name = "Get")]
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        [ProducesResponseType(StatusCodes.Status404NotFound)]
        public async Task<ActionResult<Blog>> GetAsync(string blogId) {
            if (string.IsNullOrEmpty(blogId)) {
                return BadRequest();
            }

            var blog = await DDBContext.LoadAsync<Blog>(blogId);
            if (blog == null) {
                return NotFound();
            }

            return blog;
        }

        // PUT: blog
        [HttpPut]
        [ProducesResponseType(StatusCodes.Status202Accepted)]
        public async Task<ActionResult> PutAsync([FromBody] Blog blog) {
            blog.Id = Guid.NewGuid().ToString();
            blog.CreatedTimestamp = DateTime.Now;

            await DDBContext.SaveAsync<Blog>(blog);

            return Accepted();
        }

        // DELETE: blog/blogId
        [HttpDelete("{blogId}")]
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        [ProducesResponseType(StatusCodes.Status202Accepted)]
        public async Task<ActionResult> DeleteAsync(string blogId) {
            if (string.IsNullOrEmpty(blogId)) {
                return BadRequest();
            }

            await this.DDBContext.DeleteAsync<Blog>(blogId);

            return Accepted();
        }
    }
}
```

BlogController用にlaunchSettings.jsonを変更します。

```HogeWebApi\Properties\launchSettings.json

  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:60100",
      "sslPort": 0
    }
  },
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "blog",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "HogeWebApi": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "blog",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "applicationUrl": "http://localhost:5000"
    },
    "Docker": {
      "commandName": "Docker",
      "launchBrowser": true,
      "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/blog",
      "publishAllPorts": true
    }
  }
}
```

## 実行してみる

これで準備ができました。Ready Perfectly。
これにより、以下のことが行えるようになります。

* AWSにデプロイして、API Gateway経由で.NET Core on Lambdaを呼び出せるようになる
* Testプロジェクトを実行することができる
* Mock Lambda Test Toolを使って、Lambdaのデバグが行える
* ローカルにDockerによるASP.NET Core環境を構築して、直接デバグすることができる

### AWSデプロイ

開発中に一旦デプロイしていますが、もう一度デプロイ方法を記載しておきます。

> ソリューションエクスプローラで、"Hoge"を右クリック → "Publish to AWS Lambda..."

デプロイすると、状況表示画面に"AWS Serverless URL"が表示されます。
見逃してしまった場合は、ブラウザでAWSコンソールのAPI Gatewayメニューで確認するか、AWS ExplorerのAWS CloudFormationのStackをダブルクリックします。

Serverless URLを確認したら、お好みのREST Clientツールで、以下のアドレスに"GET"メソッドでアクセスしてみます。

```
GET https://<<なんらかの文字列>>.execute-api.ap-northeast-1.amazonaws.com/Prod
```

初回起動時には、DynamoDBに何のデータも登録されていないので、空のJSON配列が返ってくるはずです。

```
[]
```

次にデータを登録してみます。同じURLにPUTしてみます。
また、本文には登録するデータを表すJsonを指定します。

```
PUT https://<<なんらかの文字列>>.execute-api.ap-northeast-1.amazonaws.com/Prod
Content-Type: text/json; charset=UTF-8

{"Name":"作者","Content":"中身"}
```

登録したデータのidがplain textで返ってくるはずです。

ここで、もう一度"GET"してみると、データが登録されているのが分かります。

```
[
  {
    "Id": "9612b9af-a4bc-45f6-a366-a33a7c03ec3d",
    "Name": "作者",
    "Content": "中身",
    "CreatedTimestamp": "2020-01-17T01:31:56.002+00:00"
  }
]
```

### テスト

最初に、プロジェクトテンプレート"AWS Serverless Application with Tests (.NET Core - C#)"内の"Blog API using DynamoDB"をテンプレートとして作成していますので、自動的にテストケースが登録されているはずです。

それでは、テストを実行してみます。

> ソリューションエクスプローラで、"Hoge.Tests"を右クリック → "テストの実行"

BlogTestAsyncが成功になっていれば、テストOKです。
すでにテスト済みになっていて、もう一度テストしたい場合には、ビルドメニューから"Hoge.Tests"をリビルドしてみてからテスト実行してください。

もちろん、テストをデバグモードで実行すると、テストコードや、そこから呼び出される本体コードをデバグすることができます。


### Mock Lambda Test Tool

Visual Studio上でMock Lambda Test Toolを使用することで、直接Lambdaをテスト/デバグすることができます。

Mock Lambda Test Toolを起動すると、デフォルトブラウザに"localhost:5050"へのアクセスが行われて、AWS .NET Mock Lambda Test Tool (Preview)が表示されます。

試しに、Visual Studio上でFunctions.csを開き、関数GetBlogsAsync (GetBlogAsyncでは無い) にブレークポイントを張ります。
そして、AWS .NET Mock Lambda Test Toolに以下のように入力して、Execute Functionを実行します。

<dl>
<dt>Config File</dt>
<dd>aws-lambda-tools-defaults.json</dd>
<dt>Function</dt>
<dd>GetBlogs</dd>
<dt>AWS Credential Profile</dt>
<dd>default</dd>
<dt>AWS Region</dt>
<dd>ap-northeast-1</dd>
<dt>Example Requests</dt>
<dd>API Gateway AWS Proxy</dd>
<dt>リクエストの中身</dt>
<dd>Get Blogsはリクエストを参照していないので、そのままでOKです。AddBlogなどをテストする場合は、適宜書き換えてください</dd>
</dl>

実行すると、ブレークポイントで停止するはずです。
そのまま処理を続行すると、Responseとして、AWS デプロイの項目で登録した内容が表示されているはずです。
また、Log Outputには、GetBlogsAsync内のcontext.Loggerに出力したログ内容が表示されています。


### Docker

Dockerを実行する場合は、docker-composeをスタートアッププロジェクトに設定します。

> ソリューションエクスプローラで、"docker-compose"を右クリック → "スタートアッププロジェクトに設定"

docker-composeをビルド (なにかうまく行かないときはリビルドも試して・・)して、デバグを開始します。

なお、コンテナとして、hogewebapiとlocaldynamodbコンテナが起動しているはずです。
コンテナウィンドウでhogewebapiをクリックして、コンテナーポート80に対応するホストポートを調べます (327xxぐらい)。
または、PowerShellなどを使って、dockerコマンドでポートを調べてもかまいません。

```
PS C:\Users\hogehoge> docker ps
CONTAINER ID        IMAGE                                             COMMAND                CREATED             STATUS              PORTS                                           NAMES
932693b5dd9f        dockercompose15818753263670802938_localdynamodb   "/bin/entrypoint.sh"   20 minutes ago      Up 20 minutes       0.0.0.0:32778->8000/tcp                         localdynamodb
375a9952a4b6        hogewebapi:dev                                    "tail -f /dev/null"    20 minutes ago      Up 16 minutes       0.0.0.0:32780->80/tcp, 0.0.0.0:32779->443/tcp   hogewebapi
PS C:\Users\hogehoge>
```

お好みのREST Clientツールで、ローカルで起動しているASP.NET Coreアプリケーションにアクセスしてみます。

```
GET http://localhost:32780/blog
```

初回起動時には、DynamoDBに何のデータも登録されていないので、空のJSON配列が返ってくるはずです。

次にデータを登録してみます。同じURLにPUTしてみます。
また、本文には登録するデータを表すJsonを指定します。

```
PUT http://localhost:32780/blog
Content-Type: text/json; charset=UTF-8

{"Name":"作者2","Content":"中身2"}
```

登録に成功すると、202 Acceptedが返ってくるはずです。

ここで、もう一度"GET"してみると、データが登録されているのが分かります。

```
[
  {
    "id": "7cc5b03d-639d-40e8-8692-22b99e779c02",
    "name": "作者2",
    "content": "中身2",
    "createdTimestamp": "2020-01-17T03:16:42.561+00:00"
  }
]
```

もちろん、ブレークポイントを使ってデバグをすることもできます。
例えば、HogeWebApi/Controllerse/BlogController.csの各メソッドで試すことができます。


## おまけ(GitHub)

作成したプロジェクトをGitHubに保存しておきます。

拡張機能としてVisual Studio Marketplaceから、"GitHub Extension for Visual Studio"をインストールします。

> "拡張機能"メニュー → "拡張機能の管理" → "GitHub Extension for Visual Studio"を検索してインストール

次に表示メニューからチームエクスプローラーを選択し、GitHubに接続します。

> "表示"メニュー  → "チームエクスプローラー" → "GitHub" → GitHubアカウントでサインイン

必要であれば、Git設定を変更します(ユーザー名、メールアドレス、既定のリポジトリの場所 (今回作成したHogeソリューションの一つ上を指定))。
そして、ソリューション"Hoge"を右クリックして、"ソリューションをソース管理に追加"を選びます。
すると、「現在のソリューションには、ソリューションフォルダー外にあるなんとかかんとか統合してください。」とかいうダイアログが表示されますが、無視して"OK"ボタンを押してください。

チームエクスプローラーから"同期"を選んで、リポジトリ名などを入力すれば、GitHubへのPushが始まります。

こうしてできたリポジトリがこちらになります。

https://github.com/dynamitecoolguy/Hoge


## 修正履歴

まだありません