Blazor WebAssembly 初期プロジェクト構成の入門

#はじめに
この記事は初期のプロジェクト構成内で説明可能な内容をまとめています。

#ソリューションの構成
- Qiita.Client: クライアント側の処理
- Qiita.Server: サーバー側の処理
 - ログインやアカウント登録などはこっち
- Qiita.Shared: 両サイドで使われる処理
 - 共通関数や、Model定義など

#クライアント側
### ・`Pages/Index.razor`

```
@page "/"

<h1>Hello, world!</h1>

Welcome to your new app.

<SurveyPrompt Title="How is Blazor working for you?" />
``` 
`@page "/"`はアクセスURL<br>
`<h1>Hello, world!</h1>`や`Welcome to your new app.`はHTML分をそのまま使える。<br>
`<SurveyPrompt Title="How is Blazor working for you?" />`は`SurveyPrompt `という名前のコンポーネントを設置し、`Title`という変数に`How is Blazor working for you?`を代入している。

### ・`Shared/SurveyPrompt.razor`
```
<div class="alert alert-secondary mt-4" role="alert">
    <span class="oi oi-pencil mr-2" aria-hidden="true"></span>
    <strong>@Title</strong>

    <span class="text-nowrap">
        Please take our
        <a target="_blank" class="font-weight-bold" href="https://go.microsoft.com/fwlink/?linkid=2137916">brief survey</a>
    </span>
    and tell us what you think.
</div>

@code {
    // Demonstrates how a parent component can supply parameters
    [Parameter]
    public string Title { get; set; }
}
```
`<div> ～ </div> `は通常のHTMLやBootstrapを使っている。<br>
`@code { ～ }`内にはC#コードを記述する。※HTMLの中でC#コードを使うには`@Title`のように`@`を使用する。
`[Parameter]`は変数につける事で、呼ばれ元で設定が出来るようにする印。

### ・`Counter.razor`
```
@page "/counter"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}
```
`<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>`は、`@onclick="IncrementCount"`の所で、クリックしたときに`IncrementCount`関数が実行されるように指定されている。

`@currentCount`はC#の変数が使われているが、`IncrementCount`関数が実行されるとインクリメントされ即時にGUIに反映される事をデバックすると確認出来る。

### ・`FetchData.razor`
```
@page "/fetchdata"
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using Qiita.Shared
@attribute [Authorize]
@inject HttpClient Http

<h1>Weather forecast</h1>

<p>This component demonstrates fetching data from the server.</p>

@if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Date</th>
                <th>Temp. (C)</th>
                <th>Temp. (F)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var forecast in forecasts)
            {
                <tr>
                    <td>@forecast.Date.ToShortDateString()</td>
                    <td>@forecast.TemperatureC</td>
                    <td>@forecast.TemperatureF</td>
                    <td>@forecast.Summary</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private WeatherForecast[] forecasts;

    protected override async Task OnInitializedAsync()
    {
        try
        {
            forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
    }

}
```
`@using`とする事で通常のC#の名前空間を設定出来る。
`@attribute [Authorize]`とする事でこのページにはログインして認証済のアカウントしかアクセスが出来なくなる。
`@inject HttpClient Http`は、`HttpClient`が依存注入される。※依存注入が不明な方は、Newされたインスタンスがセットされるようなイメージでまずは問題なし。
`@if (forecasts == null)`のようにif分は`@if{ ～ }`と書く。 この例ではforecastsがnullとそうではないときで表示内容を切り替えている。 デバックすると分かるが切り替えは瞬時。
`@foreach (var forecast in forecasts)`のようにforeach文は`@foreach (var forecast in forecasts){ ～ }と書く。

`protected override async Task OnInitializedAsync()`は、ページを開いた際のロードイベント。
`await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");`で`WeatherForecastController`の`Get`メソッドを呼び出し、`WeatherForecast[]`で結果を受け取っている。

### ・`MainLayout.razor`
```
@inherits LayoutComponentBase

<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>

    <div class="main">
        <div class="top-row px-4 auth">
            <LoginDisplay />
            <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
        </div>

        <div class="content px-4">
            @Body
        </div>
    </div>
</div>
```
`@inherits ～`で継承している。
サイドバーには`NavMenu`コンポーネント、ヘッダーには`LoginDisplay`コンポーネントを表示させている。

`@Body`には各ページの内容が入る。

### ・`Program.cs`
今後機能を追加していく中で設定を追加していくことになる。

#サーバー側
### ・`WeatherForecastController.cs`
```
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Qiita.Shared;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Qiita.Server.Controllers
{
    [Authorize]
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

        private readonly ILogger<WeatherForecastController> _logger;

        public WeatherForecastController(ILogger<WeatherForecastController> logger)
        {
            _logger = logger;
        }

        [HttpGet]
        public IEnumerable<WeatherForecast> Get()
        {
            var rng = new Random();
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }
}
```
`[Authorize]`をつける事で認証済のアカウントしかこのWebApiを使えないようになる。

`public WeatherForecastController(ILogger<WeatherForecastController> logger)`は、コンストラクタで`ILogger`を依存注入している。

`[HttpGet]`で、この関数はGetリクエストを受ける関数であると定義している。

### ・`Areas`フォルダ
ログインやアカウント作成ページなどの認証系のページが入るフォルダ。 デフォルトでは全て英語で表示されるため翻訳が必要になると思われるが、このフォルダにソースを入れ翻訳していくこととなる。

### ・`Data/ApplicationDbContext.cs`
```
using IdentityServer4.EntityFramework.Options;
using Microsoft.AspNetCore.ApiAuthorization.IdentityServer;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Qiita.Server.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Qiita.Server.Data
{
    public class ApplicationDbContext : ApiAuthorizationDbContext<ApplicationUser>
    {
        public ApplicationDbContext(
            DbContextOptions options,
            IOptions<OperationalStoreOptions> operationalStoreOptions) : base(options, operationalStoreOptions)
        {
        }
    }
}
```
コードファーストでDBを更新していく場合などに使用していく。

### ・`Models/ApplicationUser.cs`
```
using Microsoft.AspNetCore.Identity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Qiita.Server.Models
{
    public class ApplicationUser : IdentityUser
    {
    }
}
```
AspNetUsersテーブルにカラムを追加したいときなどに、このファイルに記載する。

### ・`Startup.cs`
いろいろな設定を追加したり、依存注入をする際に使用していく。

<br>
[Blazor関連のリンク]
[Blazor WebAssembly プロジェクト作成(認証あり)](https://qiita.com/pero_88/items/be142d5d0ba92e5c91d0)
[Blazor WebAssembly 初期プロジェクト構成の入門](https://qiita.com/pero_88/items/ced1028ad536a43fec1d)
[Blazor WebAssembly Postgresを使うまで](https://qiita.com/pero_88/items/23e88a1d2bc3659b9946)
[Blazor WebAssembly コードビハインド](https://qiita.com/pero_88/items/be871f4ac63868f048f0)
[Blazor WebAssembly InputSelectの使い方](https://qiita.com/pero_88/items/3eddcd1aedf8bbc8441b)