MySqlとBlazorをdocker-composeで動かしてみる

## はじめに

MySqlとBlazorをdocker-compose動かしてみたいと思います。

Blazorの開発環境の構築は[こちら](https://qiita.com/taskeknight/items/f07d23151b8bd23e456d)

ASP.NET Core Blazor のホスティング モデルで構築しています。
ブラウザ側ではWebAssembly ベースの .NET ランタイム(Blazor WebAssembly) が動作してます。

MySqlを読み込ませるコードを追加していきます。

## サーバ側のコード

サーバ側に`api/MySql`でアクセスするコントローラを作成します。MySqlにアクセスして、データを取得します。

```C#:BrazorwasmDotNetCoreHostedWithDocker.Server.Controllers.MySQLController.cs
using BrazorwasmDotNetCoreHostedWithDocker.Shared;
using Microsoft.AspNetCore.Mvc;
using MySql.Data.MySqlClient;
using SqlKata.Compilers;
using SqlKata.Execution;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace BrazorwasmDotNetCoreHostedWithDocker.Server.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class MySqlController : ControllerBase
    {
        [HttpGet]
        public async Task<IEnumerable<MySqlData>> Get()
        {
            MySqlConnectionStringBuilder builder = new MySqlConnectionStringBuilder
            {
                Server = "mysql",
                Database = "MyDatabase",
                UserID = "root",
                Password = "root1234",
                SslMode = MySqlSslMode.Required,
            };

            IEnumerable<MySqlData> list = null;
            using (MySqlConnection connection = new MySqlConnection(builder.ConnectionString))
            {
                await connection.OpenAsync();

                MySqlCompiler compiler = new MySqlCompiler();
                QueryFactory db = new QueryFactory(connection, compiler);

                list = db.Query("MyData").Select("Id", "Title", "CreatedAt").Get<MySqlData>();
            }

            return list;
        }
    }
}

```

今回はSqlKataというライブラリを利用しています。
https://sqlkata.com/

内部的にはDapperが使われているようで、データをGetする際にクラスを指定するとちゃんとオブジェクト化してくれました。すごく可読性がよく使いやすそうな印象でした。

## クライアント側のコード

`/mysql`でアクセスできるようにClient側を修正していきたいと思います。
ナビゲーションに`mysql`を追加します。

```C#:BrazorwasmDotNetCoreHostedWithDocker.Client.Shard.NavMenu.razor
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
・・・
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="mysql">
                <span class="oi oi-list-rich" aria-hidden="true"></span> MySql
            </NavLink>
        </li>
    </ul>
・・・
</div>
```

```C#:BrazorwasmDotNetCoreHostedWithDocker.Client.Pages.MySql.razor
@page "/mysql"
@using BrazorwasmDotNetCoreHostedWithDocker.Shared
@inject HttpClient Http

@code {
    private MySqlData[] data;

    protected override async Task OnInitializedAsync()
    {
        data = await Http.GetFromJsonAsync<MySqlData[]>("api/MySql");
    }
}

<h1>MySql</h1>

@if (data == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Id</th>
                <th>Title</th>
                <th>CreatedAt</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var value in data)
            {
                <tr>
                    <td>@value.Id</td>
                    <td>@value.Title</td>
                    <td>@value.CreatedAt.ToShortDateString()</td>
                </tr>
            }
        </tbody>
    </table>
}

```

## 共通のコード

```C#:BrazorwasmDotNetCoreHostedWithDocker.Shared.MySqlData.cs
using System;

namespace BrazorwasmDotNetCoreHostedWithDocker.Shared
{
    public class MySqlData
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public DateTime CreatedAt { get; set; }
    }
}
```

# docker-composeの設定

```yml:docker-compose.yml
version: '3.7'
services:
    db:
        container_name: mysql
        image: mysql
        ports:
            - "3306:3306"
        volumes:
            - ./db/mysql_init:/docker-entrypoint-initdb.d
            - ./db/mysql_data:/var/lib/mysql
            - ./db/mysql_conf/:/etc/mysql/conf.d
        environment:
            MYSQL_ROOT_PASSWORD: root1234
            MYSQL_USER: test
            MYSQL_PASSWORD: test1234
        command: >
            mysqld
                --character-set-server=utf8
                --collation-server=utf8_unicode_ci
                --skip-character-set-client-handshake
    app:
        container_name: brazor
        build:
            context: .
            dockerfile: Dockerfile
        ports:
            - "80:80"
        environment:
            ASPNETCORE_ENVIRONMENT: Development
```

`ASPNETCORE_ENVIRONMENT: Development`で開発者モードにすることができます。

## MySqlの設定

ソリューションフォルダの配下に、MySql用のファイルを格納しています（Visual Stadio上で作らない方がいいかもしれません）。

```
├─db
   ├─mysql_conf
   │      default_authentication.cnf
   │      
   ├─mysql_data
   │      
   └─mysql_init
           1_create.sql
           2_insert.sql
```

`/docker-entrypoint-initdb.d`の下に格納すれば、最初に実行してもらえますので、
`docker-compose.yml`の中で、`mysql_init`にマウントされるように設定しています。

`MyDatabase`というデータベース、そこに`MySqlData`というテーブルを作成して、
データをInsertしています。

```sql:1_create.sql
CREATE DATABASE MyDatabase;
use MyDatabase;

CREATE TABLE MySqlData (
    Id INT(11) AUTO_INCREMENT NOT NULL,
    Title VARCHAR(64) NOT NULL,
    CreatedAt Date NOT NULL,
    PRIMARY KEY (id));
```

```sql:2_insert.sql
use MyDatabase;

INSERT INTO MySqlData (Title, CreatedAt) VALUES ('タイトル１', '2020-10-10');
INSERT INTO MySqlData (Title, CreatedAt) VALUES ('タイトル２', '2020-10-11');
```

日本語で登録したかったので、`docker-compose.yml`の中でutf8になるように設定しています。

```yml
            mysqld
                --character-set-server=utf8
                --collation-server=utf8_unicode_ci
                --skip-character-set-client-handshake  # 強制上書き
```

# 起動

```PowerShell
docker-compose up --build
```

`http://localhost/mysql`にアクセスして、下記画面が出れば成功です。

![キャプチャ.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624898/a35d665b-0202-34ba-470c-08184198bac5.jpeg)

# その他メモ

## コンテナに入るとき

```
docker-compose exec db bash
```

## MySqlにアクセス

```
mysql -u root -p
```