Asp.net core 2.2 のチュートリアルを単体テストのサンプルの構成で試してCentos7.6 + Sql Serverで動かしたメモ

## 概要

[単体テストのサンプル](https://docs.microsoft.com/ja-jp/aspnet/core/mvc/controllers/testing?view=aspnetcore-2.2)と[Mvcチュートリアル](https://docs.microsoft.com/ja-jp/aspnet/core/tutorials/first-mvc-app/start-mvc?view=aspnetcore-2.2&tabs=visual-studio)のフォルダ構成が異なっていたので、単体テストの構成でチュートリアルを試してみる。
ついでにCentOS上で動かしてみる。

環境の準備については以下。
[sql serverの準備](https://qiita.com/hibohiboo/items/dd8cf15ece32f0591b03)
[visual studio + dotnet core 2.2](https://qiita.com/hibohiboo/items/1d1b5922b3e1de23dffa)

## 環境

* Windows 10
* Visual Studio 2017 Community
* Vagrant 2.2.4
* virtualbox 6.0.6r130049

## ディレクトリ構成

```
[vagrant@localhost vagrant]$ tree .
.
├── MvcMovie
│   ├── MvcMovie ... Asp.net プロジェクト
│   │   ├── Areas ... 以下、認証のスキャフォールディングで追加されるファイル
│   │   │   └── Identity
│   │   │       ├── Data
│   │   │       │   └── MvcMovieIdentityContext.cs
│   │   │       ├── IdentityHostingStartup.cs
│   │   │       └── Pages
│   │   ├── Controllers ... コントローラ
│   │   │   ├── HelloWorldController.cs
│   │   │   ├── HomeController.cs
│   │   │   └── MoviesController.cs
│   │   ├── Core ... モデルとインターフェース
│   │   │   ├── Interfaces
│   │   │   │   ├── IMovieRepository.cs
│   │   │   │   └── IRepository.cs
│   │   │   └── Models
│   │   │       ├── ErrorViewModel.cs
│   │   │       └── Movie.cs
│   │   ├── Data
│   │   │   └── MvcMovieContext.cs
│   │   ├── Infrastructure ... リポジトリ
│   │   │   ├── MovieRepository.cs
│   │   │   └── Repository.cs
│   │   ├── Migrations ... マイグレーション
│   │   ├── MvcMovie.csproj
│   │   ├── MvcMovie.csproj.user
│   │   ├── Program.cs
│   │   ├── Properties ... 発行で使用
│   │   │   ├── PublishProfiles
│   │   │   │   ├── FolderProfile.pubxml
│   │   │   │   └── FolderProfile.pubxml.user
│   │   │   └── launchSettings.json
│   │   ├── ScaffoldingReadme.txt
│   │   ├── Startup.cs
│   │   ├── Views
│   │   │   ├── HelloWorld
│   │   │   │   └── Index.cshtml
│   │   │   ├── Home
│   │   │   │   ├── Index.cshtml
│   │   │   │   └── Privacy.cshtml
│   │   │   ├── Movies
│   │   │   │   ├── Create.cshtml
│   │   │   │   ├── Delete.cshtml
│   │   │   │   ├── Details.cshtml
│   │   │   │   ├── Edit.cshtml
│   │   │   │   └── Index.cshtml
│   │   │   ├── Shared
│   │   │   │   ├── Error.cshtml
│   │   │   │   ├── _CookieConsentPartial.cshtml
│   │   │   │   ├── _Layout.cshtml
│   │   │   │   ├── _LoginPartial.cshtml
│   │   │   │   └── _ValidationScriptsPartial.cshtml
│   │   │   ├── _ViewImports.cshtml
│   │   │   └── _ViewStart.cshtml
│   │   ├── appsettings.Development.json
│   │   ├── appsettings.json
│   │   ├── bin
│   │   │   ├── Debug
│   │   │   └── Release
│   │   │       └── netcoreapp2.2
│   │   │           └── publish ... 発行の出力先
│   │   ├── obj
│   ├── MvcMovie.Test ... テストプロジェクト
│   │   ├── Controllers
│   │   │   └── MovieControllerTest.cs
│   │   ├── MvcMovie.Test.csproj
│   │   ├── UnitTest1.cs
│   │   ├── bin
│   │   └── obj
│   └── MvcMovie.sln
├── Vagrantfile
├── bin
│   └── up.sh
├── docker
│   ├── docker-compose.yml
│   └── nginx
│       ├── Dockerfile
│       └── default.conf
└── provision
    ├── bash
    │   └── install_ansible.sh
    ├── docker
    │   └── docker-compose.yml
    └── playbooks
```


## 実践

### ソリューションの作成

[作成時点](https://github.com/hibohiboo/develop/tree/df39480012315ce0bb76dcefb0ba6f3ac9510a58/tutorial/lesson/dotnet/tutorial22/)

### コントローラの追加

[コントローラ追加](https://docs.microsoft.com/ja-jp/aspnet/core/tutorials/first-mvc-app/adding-controller?view=aspnetcore-2.2&tabs=visual-studio)
[コントローラ追加時点ソース](https://github.com/hibohiboo/develop/tree/df39480012315ce0bb76dcefb0ba6f3ac9510a58/tutorial/lesson/dotnet/tutorial22/)。[書き換え時点ソース](https://github.com/hibohiboo/develop/tree/5fdc4adb33efb05a90f522024adb92ab9eb81421/tutorial/lesson/dotnet/tutorial22/)

### ビューの追加

[ビューの追加](https://docs.microsoft.com/ja-jp/aspnet/core/tutorials/first-mvc-app/adding-view?view=aspnetcore-2.2&tabs=visual-studio)
* 日本語のVisual Studioでは[view]ではなく[ビュー]を検索する

### モデルの追加
単体テストのチュートリアルでは、ModelはCoreの下にあるので、フォルダと名前空間を変更する。
Core/Models/Movie.csを作成。
[モデルの追加](https://docs.microsoft.com/ja-jp/aspnet/core/tutorials/first-mvc-app/adding-model?view=aspnetcore-2.2&tabs=visual-studio)
[フォルダ変更](https://github.com/hibohiboo/develop/tree/3bda4665e69ed6856592263a7edda56781403618/tutorial/lesson/dotnet/tutorial22/)。[スキャフォールディング追加後ソース](https://github.com/hibohiboo/develop/tree/0db3a117e4358fdbcfca7f000c731d9455e5b8ea/tutorial/lesson/dotnet/tutorial22/)。[エラー発生中ソース](https://github.com/hibohiboo/develop/tree/7b0ae3971cb17f7890bb88516dbc94c4aaa74c9f/tutorial/lesson/dotnet/tutorial22/)。

このままだとDBエラーなのでマイグレーション。

```
PM> Add-Migration Initial
PM> Update-Database
```

![2019-05-19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/fdba1697-604e-490d-0fbc-3c34bdbfd4fe.png)
[DBマイグレーション後ソース](https://github.com/hibohiboo/develop/tree/11493dfe5593b8b5c3a1d5b44be8227b3d3c33bd/tutorial/lesson/dotnet/tutorial22/)

### リポジトリ作成
単体テストのチュートリアルでは、リポジトリパターンを使っているので、スキャフォールディングで作られたソースを修正する。
インターフェースはCore/Interfacesに、リポジトリはInfrastructureに作成する。
[リポジトリパターン追加時ソース](https://github.com/hibohiboo/develop/tree/e6ba060570168e7eadedcce66df22d829f50cabd/tutorial/lesson/dotnet/tutorial22/)

#### インターフェース作成
 
```csharp:Core/Interfaces/IRepository.cs
using System.Collections.Generic;
using System.Threading.Tasks;

namespace MvcMovie.Core.Interfaces
{
    public interface IRepository<Type, Key>
    {
        Task<Type> GetByIdAsync(Key key);
        Task<List<Type>> ListAsync();
        Task AddAsync(Type type);
        Task UpdateAsync(Type type);
        Task DeleteAsync(Type type);
        bool Exists(Key key);
    }
}
```

```csharp:Core/Interfaces/IMovieRepository.cs
using MvcMovie.Core.Models;

namespace MvcMovie.Core.Interfaces
{
    public interface IMovieRepository : IRepository<Movie, int> { }
}
```

#### リポジトリ作成

```csharp:Core/Infrastructure/Repository.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using MvcMovie.Core.Interfaces;
using System.Threading;
using System.Linq.Expressions;

namespace MvcMovie.Infrastructure
{
    public abstract class Repository<Type, Key> : IRepository<Type, Key>
        where Type : class
    {
        private readonly DbContext _dbContext;

        public Repository(DbContext dbContext)
        {
            _dbContext = dbContext;
        }

        public abstract Task<Type> GetByIdAsync(Key key);
        protected Task<Type> GetByIdAsync(Expression< Func<Type, bool>> func)
        {
            return _dbContext.Set<Type>().FirstOrDefaultAsync(func, default(CancellationToken));
        }

        public Task<List<Type>> ListAsync()
        {
            var movies = from m in _dbContext.Set<Type>()
                         select m;

            return movies.ToListAsync();

        }

        public Task AddAsync(Type type)
        {
            _dbContext.Add(type);
            return _dbContext.SaveChangesAsync();
        }

        public Task UpdateAsync(Type type)
        {
            _dbContext.Update(type);
            return _dbContext.SaveChangesAsync();
        }

        public Task DeleteAsync(Type type)
        {
            _dbContext.Set<Type>().Remove(type);
            return _dbContext.SaveChangesAsync();
        }
        public abstract bool Exists(Key key);
        protected bool Exists(Predicate<Type> func)
        {
            return _dbContext.Set<Type>().ToList().Exists(func);
        }
    }
}
```

```csharp:Infrastructure/MovieRepository.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using MvcMovie.Core.Interfaces;
using MvcMovie.Core.Models;
using MvcMovie.Models;

namespace MvcMovie.Infrastructure
{
    public class MovieRepository :  Repository<Movie, int>, IMovieRepository
    {
        private readonly MvcMovieContext _dbContext;

        public MovieRepository(MvcMovieContext dbContext):base(dbContext)
        {
            _dbContext = dbContext;
        }

        public override Task<Movie> GetByIdAsync(int id)
        {
            return this.GetByIdAsync(m => m.Id == id);
        }

        public override bool Exists(int id)
        {
            return this.Exists(e => e.Id == id);
        }
    }
}
```

#### コントローラ修正


```diff:Controllers/MoviesController.cs
+﻿using System.Threading.Tasks;
+﻿using MvcMovie.Core.Interfaces;

 namespace MvcMovie.Controllers
 {
     public class MoviesController : Controller
     {
-        private readonly MvcMovieContext _context;
+        private readonly IMovieRepository _movieRepository;

-        public MoviesController(MvcMovieContext context)
+        public MoviesController(IMovieRepository context)
         {
-            _context = context;
+            _movieRepository = context;
         }

+
         // GET: Movies
         public async Task<IActionResult> Index()
         {
-            return View(await _context.Movie.ToListAsync());
+            return View(await _movieRepository.ListAsync());
         }

         // GET: Movies/Details/5
@@ -33,8 +30,7 @@ namespace MvcMovie.Controllers
                 return NotFound();
             }

-            var movie = await _context.Movie
-                .FirstOrDefaultAsync(m => m.Id == id);
+            var movie = await _movieRepository.GetByIdAsync((int)id);
             if (movie == null)
             {
                 return NotFound();
@@ -58,8 +54,7 @@ namespace MvcMovie.Controllers
         {
             if (ModelState.IsValid)
             {
-                _context.Add(movie);
-                await _context.SaveChangesAsync();
+                await _movieRepository.AddAsync(movie);
                 return RedirectToAction(nameof(Index));
             }
             return View(movie);
@@ -73,7 +68,7 @@ namespace MvcMovie.Controllers
                 return NotFound();
             }

-            var movie = await _context.Movie.FindAsync(id);
+            var movie = await _movieRepository.GetByIdAsync((int)id);
             if (movie == null)
             {
                 return NotFound();
@@ -97,12 +92,11 @@ namespace MvcMovie.Controllers
             {
                 try
                 {
-                    _context.Update(movie);
-                    await _context.SaveChangesAsync();
+                    await _movieRepository.UpdateAsync(movie);
                 }
                 catch (DbUpdateConcurrencyException)
                 {
-                    if (!MovieExists(movie.Id))
+                    if (!_movieRepository.Exists(movie.Id))
                     {
                         return NotFound();
                     }
@@ -124,8 +118,8 @@ namespace MvcMovie.Controllers
                 return NotFound();
             }

-            var movie = await _context.Movie
-                .FirstOrDefaultAsync(m => m.Id == id);
+            var movie = await _movieRepository.GetByIdAsync((int)id);
+
             if (movie == null)
             {
                 return NotFound();
@@ -139,15 +133,9 @@ namespace MvcMovie.Controllers
         [ValidateAntiForgeryToken]
         public async Task<IActionResult> DeleteConfirmed(int id)
         {
-            var movie = await _context.Movie.FindAsync(id);
-            _context.Movie.Remove(movie);
-            await _context.SaveChangesAsync();
+            var movie = await _movieRepository.GetByIdAsync((int)id);
+            await _movieRepository.DeleteAsync(movie);
             return RedirectToAction(nameof(Index));
         }
-
-        private bool MovieExists(int id)
-        {
-            return _context.Movie.Any(e => e.Id == id);
-        }
  
```

#### リポジトリを依存性注入(DI)
依存性注入 (Dependency Injection) の設定をする。

```diff:Startup.cs
+using MvcMovie.Core.Interfaces;
+using MvcMovie.Infrastructure;
// 省略
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });


            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            services.AddDbContext<MvcMovieContext>(options =>
                    options.UseSqlServer(Configuration.GetConnectionString("MvcMovieContext")));

+            services.AddScoped<IMovieRepository, MovieRepository>();
        }
```

### 単体テストのチュートリアル

[小さくわける命名規則](https://docs.microsoft.com/ja-jp/dotnet/standard/modern-web-apps-azure-architecture/test-asp-net-core-mvc-apps#test-naming)ほど今回は分割していない。この命名規則を使うなら、src/MvcMovieとtests/UnitTests/MvcMovie.UnitTestのようになるか。今回はMvcMovie.Testで作成する。

#### テストプロジェクトの追加

以下を参考に、テストプロジェクトを追加する

* [ASP.NET Core のコントローラーのロジックをテストする](https://docs.microsoft.com/ja-jp/aspnet/core/mvc/controllers/testing?view=aspnetcore-2.2)
* [ASP.NET Core MVC アプリのテスト](https://docs.microsoft.com/ja-jp/dotnet/standard/modern-web-apps-azure-architecture/test-asp-net-core-mvc-apps)

* [ファイル] >  [新規作成] > [Project]
* xUnitテストプロジェクトを選択
  * 名前: MvcMovie.Test
  * ソリューション: ソリューションに追加
  * ソリューションのディレクトリを作成のチェックを外す
![2019-05-19 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/adf177b3-b00f-162c-bd6b-88818af5650c.png)

[テストプロジェクト追加時ソース](https://github.com/hibohiboo/develop/tree/6fe20286f99d4ab7aa766a6d1525f7aa74053d03/tutorial/lesson/dotnet/tutorial22/)

#### テストの追加
* 以下のようなソースを作成する
* この時点だと依存関係が解決されていないため、依存関係を解決してやる

[コントローラのテスト追加時ソース](https://github.com/hibohiboo/develop/tree/ac9e1f3603bbfa56565c6480863f223f8b096d46/tutorial/lesson/dotnet/tutorial22/)

```Controllers/MovieControllerTest.cs
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Moq;
using MvcMovie.Controllers;
using MvcMovie.Core.Interfaces;
using MvcMovie.Core.Models;
using Xunit;
using System.Linq;

namespace MvcMovie.Test.Controllers
{
    public class MovieControllerTest
    {
        [Fact]
        public async Task Index_Movieが１つ入ったモデルをもったViewResultが返ること()
        {
            // Arrange
            var mockRepo = new Mock<IMovieRepository>();
            var movies = new List<Movie> { new Movie { Id = 1, Title = "test", Genre = "Test", Price = 10 } };
            mockRepo.Setup(repo => repo.ListAsync(""))
                .ReturnsAsync(movies);

            MoviesController controller = new MoviesController(mockRepo.Object);

            // Act
            var result = await controller.Index("");

            // Assert
            var viewResult = Assert.IsType<ViewResult>(result);
            var model = Assert.IsAssignableFrom<IEnumerable<Movie>>(
                viewResult.ViewData.Model);
            Assert.Equal(1, model.Count());
        }

    }
}
```

#### MvcMovieの参照の追加

プロジェクトを右クリックし、[追加]>[参照]>[プロジェクト]>[MvcMovie]

![choose_参照.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/c6529d17-8abe-b74f-8c01-3ecdbc6c59c4.gif)

#### Moqの参照の追加
リポジトリとコントローラを切り離すためのモックを作るライブラリを追加する。
プロジェクトを右クリックし、[追加]>[Nugetパッケージの管理]。
Moqで検索。インストール。

![choose_参照_moq.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/e9836191-fae2-9384-5880-08e5cbbbf678.gif)

#### Microsoft.AspNetCore.Mvc.Abstractionsの参照の追加
プロジェクトを右クリックし、[追加]>[Nugetパッケージの管理]。
Microsoft.AspNetCore.Mvc.Abstractionsで検索。インストール。
![2019-05-19 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/dbb51347-fd86-53ef-39fb-1a4f13a26b6c.png)
#### Microsoft.AspNetCore.Mvc.ViewFeaturesの参照の追加
プロジェクトを右クリックし、[追加]>[Nugetパッケージの管理]。
Microsoft.AspNetCore.Mvc.Abstractionsで検索。インストール。

#### テストの実行
* [テスト]>[実行]>[すべてのテスト]
* テストエクスプローラーを確認
![2019-05-19 (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/de136d03-8e2d-4f09-4ee0-7c13b4b22de9.png)

環境の準備については以下。
[sql serverの準備](https://qiita.com/hibohiboo/items/dd8cf15ece32f0591b03)

### 認証

#### 認証のスキャフォールディング
[認証のスキャフォールディング](https://docs.microsoft.com/ja-jp/aspnet/core/security/authentication/scaffold-identity?view=aspnetcore-2.2&tabs=visual-studio#scaffold-identity-into-an-mvc-project-without-existing-authorization)

* ログイン・ログアウト・登録の機能を追加。
* 同じ名前のContextは付けられないので別の名前のcontextを付ける。今回はMvcMovieIdentityContext

![Identityの追加.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/df6b3404-6b16-c7ab-2a70-f77d4633ce8b.gif)

[認証スキャフォールディング後ソース](https://github.com/hibohiboo/develop/tree/e86e3fc92302ab1a98754c0fef188b78941c9bea/tutorial/lesson/dotnet/tutorial22/)

#### 承認の有効化

```diff
--- a/tutorial/lesson/dotnet/tutorial22/MvcMovie/MvcMovie/Startup.cs
+++ b/tutorial/lesson/dotnet/tutorial22/MvcMovie/MvcMovie/Startup.cs
@@ -55,6 +55,7 @@ namespace MvcMovie

             app.UseHttpsRedirection();
             app.UseStaticFiles();
+            app.UseAuthentication();
             app.UseCookiePolicy();

             app.UseMvc(routes =>
diff --git a/tutorial/lesson/dotnet/tutorial22/MvcMovie/MvcMovie/Views/Shared/_Layout.cshtml b/tutorial/lesson/dotnet/tutorial22/MvcMovie/MvcMovie/Views/Shared/_Layout.cshtml
index c9d790b..9a13c2c 100644
--- a/tutorial/lesson/dotnet/tutorial22/MvcMovie/MvcMovie/Views/Shared/_Layout.cshtml
+++ b/tutorial/lesson/dotnet/tutorial22/MvcMovie/MvcMovie/Views/Shared/_Layout.cshtml
@@ -35,6 +35,7 @@
                             <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
                         </li>
                     </ul>
+                    <partial name="_LoginPartial" />
                 </div>
             </div>
         </nav>
```

[承認有効化後ソース](https://github.com/hibohiboo/develop/tree/cb193e5a001a6f04872c299580ab3a15d598b4db/tutorial/lesson/dotnet/tutorial22/)


#### DBの更新

チュートリアル通りにすると、すでにDbコンテキストがあるためエラーとなる。

```
PM> Update-Database
More than one DbContext was found. Specify which one to use. Use the '-Context' parameter for PowerShell commands and the '--context' parameter for dotnet commands.
```

以下のように具体的に指定する。

```
PM> Add-Migration CreateIdentitySchema -Context MvcMovieIdentityContext
PM> Update-Database -Context MvcMovieIdentityContext
```

### データベースへの接続
#### データベース準備
ここまでローカルでやってきたが、SqlServerで試してみる。
[sql serverの準備](https://qiita.com/hibohiboo/items/dd8cf15ece32f0591b03)
で準備したものに１つ追加する。

 ```yaml:D:playbooks/roles/mssql-server/tasks/main.yml
- name: Identity用DB
  shell: cd /vagrant/provision/docker && /usr/local/bin/docker-compose exec -T {{ docker_container_name}} /opt/mssql-tools/bin/sqlcmd -S localhost -U {{test_user_name}} -P '{{ test_user_pass }}' -Q "IF DB_ID (N'TestIdentityDB') IS NULL create database [TestIdentityDB] collate Japanese_CS_AS" 
  register: result
  changed_when: result.rc != 0
```

```
vagrant up
or すでに仮想環境を作っていた場合、
vagrant provision
```
#### 接続確認

[表示]>[Sql Server オブジェクトエクスプローラー]をクリック

![2019-05-19 (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/8918fca4-62d7-c801-b754-c16ff2612662.png)

SQL Serverを右クリックして、[SQL Serverの追加] を選択

* IP: 192.168.50.11
* SqlServer認証
* ユーザ: test_db_user
* パスワード: !test_password001
![2019-05-19 (8).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/28e0982a-c132-494c-a1a5-eba3a912fd74.png)

##### 使用するDBの確認

* TestDB, TestIdentityDBがあることを確認する。
* データベースをクリックし、表示されるプロパティから接続文字列を確認

![2019-05-19 (9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/99f9f596-ea4a-3b55-d3c9-c589acb4f7c2.png)

#### 接続の更新
[SqlServerを使用に切り替えたソース](https://github.com/hibohiboo/develop/tree/4b024aa2717d731e3d78f88a7a5683abe4d7be48/tutorial/lesson/dotnet/tutorial22/) ... ※ 認証のマイグレーションをこの時点では忘れている


```diff:appsettings.json
{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*",
    "ConnectionStrings": {
-    "MvcMovieContext": "Server=(localdb)\\mssqllocaldb;Database=MvcMovieContext-24336131-8a89-4ef3-bfde-7645e79572d5;Trusted_Connection=True;MultipleActiveResultSets=true",
-    "MvcMovieIdentityContextConnection": "Server=(localdb)\\mssqllocaldb;Database=MvcMovie;Trusted_Connection=True;MultipleActiveResultSets=true"
+        "MvcMovieContext": "Data Source=192.168.50.11;Initial Catalog=TestDB;User ID=test_db_user;Password=!test_password001;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
+        "MvcMovieIdentityContextConnection": "Data Source=192.168.50.11;Initial Catalog=TestIdentityDB;User ID=test_db_user;Password=!test_password001;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"
    }
}
```

#### DBのマイグレーション
使うDBが変わったので、再度マイグレーション

```
PM> Update-Database -Context MvcMovieContext
PM> Update-Database -Context MvcMovieIdentityContext
```

### 発行して動作確認
#### 発行

[発行](https://docs.microsoft.com/ja-jp/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-2.2)

#### vagrant の立ち上げ

```
$ vagrant up
```

#### dockerの立ち上げ

```bash:bin\up.sh
#!/bin/bash

# このシェルスクリプトのディレクトリの絶対パスを取得。
bin_dir=$(cd $(dirname $0) && pwd)
parent_dir=$bin_dir/..
docker_dir=$parent_dir/docker

# up.sh docker-compose.camp.yml
composeFile=${1:-"docker-compose.yml"}

# docker-composeの起動
cd $docker_dir && docker-compose -f $composeFile up
```

```
$ vagrant ssh
[vagrant@localhost vagrant]$ cd /vagrant/
[vagrant@localhost vagrant]$ ./bin/up.sh
```

#### 確認

ブラウザで、 http://192.168.50.11/ にアクセス。

認証を確認したら以下のエラーが。。

```
Error.
An error occurred while processing your request.
Request ID: 0HLMS1B3T1BRS:00000001

Development Mode
Swapping to Development environment will display more detailed information about the error that occurred.

The Development environment shouldn't be enabled for deployed applications. It can result in displaying sensitive information from exceptions to end users. For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development and restarting the app.
```

##### エラーの解決

`Add-Migration CreateIdentitySchema -Context MvcMovieIdentityContext`を抜かしていた。


```
PM> Add-Migration CreateIdentitySchema -Context MvcMovieIdentityContext
PM> Update-Database -Context MvcMovieIdentityContext
```

[認証のマイグレーションの追加後ソース](https://github.com/hibohiboo/develop/tree/32e18fa33f1204b270fcccdaa909de3cdb8b0151/tutorial/lesson/dotnet/tutorial22/)


ビルドしなおして、再度発行して、再度dockerを立ち上げ。
http://192.168.50.11/ で正常に動くことを確認。



## 参考

### asp dotnet core
[Visual Studio 2017の前提条件](https://docs.microsoft.com/ja-jp/dotnet/core/windows-prerequisites?tabs=netcore2x#prerequisites-with-visual-studio-2017)
[推奨ラーニングパス](https://docs.microsoft.com/ja-jp/aspnet/core/?view=aspnetcore-2.2#recommended-learning-path)
[tutorial ](https://docs.microsoft.com/ja-jp/aspnet/?view=aspnetcore-2.2#pivot=core&panel=core_tutorials)
[dotnet core guide](https://docs.microsoft.com/ja-jp/dotnet/core/)
[dotnet core hello world](https://docs.microsoft.com/ja-jp/dotnet/core/tutorials/with-visual-studio)
[asp dotnet core mvc tutorial](https://docs.microsoft.com/ja-jp/aspnet/core/tutorials/first-mvc-app/start-mvc?view=aspnetcore-2.2&tabs=visual-studio)
[sdk2.2](https://dotnet.microsoft.com/download)
[efcore tutorial](https://docs.microsoft.com/ja-jp/aspnet/core/data/ef-mvc/intro?view=aspnetcore-2.2)
[ASP.NET Core Identity をテンプレートからカスタマイズ](https://blog.nextscape.net/archives/Date/2017/12/aspnetidentity1)
[ASP.NET Identity メモ](https://qiita.com/zaburo/items/209608355b6221df5b54)
[ASP.NET Core アプリを Ubuntu サーバーで公開](https://qiita.com/yniji/items/48ede6a3f920ba26ff59)
[.NET Coreアプリをさくっと作ってコンテナにする](https://qiita.com/loftkun/items/18a6bbedd586183d3162)
[ASP.NET Core MVCを新人に説明してみよう](https://qiita.com/saxxos/items/f8bdf3a0a9d6b8e3cfef)
[CentOS 7.2上に.NET Core 1.1をインストールして、Visual StudioでビルドしたASP.NET Core Webアプリをデプロイしてサービス化する](https://qiita.com/yamaokunousausa/items/f9f2b157e0fdca045a14)
[ASP.NET Core 2.0 Authentication](https://qiita.com/masakura/items/85c59e60cac7f0638c1b)
[Test](https://www.buildinsider.net/language/dotnetcore/07)
[ASP.NET Core MVC アプリのテスト](https://docs.microsoft.com/ja-jp/dotnet/standard/modern-web-apps-azure-architecture/test-asp-net-core-mvc-apps)
[xUnit 単体テスト 入門 in .NET Core : Assert の基礎](https://blog.beachside.dev/entry/2018/11/20/183000)
[コントローラー ロジックの単体テスト](https://docs.microsoft.com/ja-jp/aspnet/core/mvc/controllers/testing?view=aspnetcore-2.2)
[ASP.NET Core MVC と xUnit.NET でユニットテストを行う Part.2](http://mrgchr.hatenablog.com/entry/2016/11/09/000000)
[コードの単体テスト](https://docs.microsoft.com/ja-jp/visualstudio/test/unit-test-your-code?view=vs-2019)
[【Linux CentOS 7】VS2017で作成したサンプル.NET Core 2.0 MVC WEBアプリをLinuxでそのまま実行させる【.NET Core 2.0】](http://akira-arets.blogspot.com/2017/08/linux-dotnetcoremvc-from-vs2017.html)
[インフラストラクチャ](https://docs.microsoft.com/ja-jp/dotnet/standard/microservices-architecture/microservice-ddd-cqrs-patterns/infrastructure-persistence-layer-implemenation-entity-framework-core#implement-custom-repositories-with-entity-framework-core)
[moq で 非同期メソッドの返り値を設定する](http://kuxumarin.hatenablog.com/entry/2017/07/22/moq_%E3%81%A7_%E9%9D%9E%E5%90%8C%E6%9C%9F%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%81%AB%E8%BF%94%E3%81%99%E5%80%A4%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B)
[テスト エクスプローラーでテストを実行する](https://docs.microsoft.com/ja-jp/visualstudio/test/unit-test-basics?view=vs-2019#run-tests-in-test-explorer)
[ASP.NET MVC の Repository パターン再考](https://blog.karamem0.jp/entry/2016/11/01/190000) .. DbContextのMockの作り方例
[ASP.NET Core Web API – Repository Pattern](https://code-maze.com/net-core-web-development-part4/)
[コードカバレッジの導入](http://kouki-hoshi.hatenablog.com/entry/2017/05/20/060526)
[dotnet core 2.2 docker image](https://docs.microsoft.com/ja-jp/aspnet/core/migration/21-to-22?view=aspnetcore-2.2&tabs=visual-studio#update-docker-images)
[dotnet command](https://docs.microsoft.com/ja-jp/dotnet/core/tools/dotnet-run?tabs=netcore21)
[複数のdcoker-compose で同じコンテナ内](https://tech.actindi.net/2018/12/21/100000)
[ASP .NET Core で作った Web API を Linux サーバーでホストしてみる](https://blog.kazuakix.jp/entry/2018/02/03/172328)
[portなど](https://stackoverflow.com/questions/45211286/using-appsettings-json-to-configure-kestrel-listen-port-dotnet-core-2-preview-2)
[ASP.NET CoreのWebApplicationを外部公開](https://qiita.com/husky774rr/items/256609e9d126653274f0)
[Asp.net Identity](https://docs.microsoft.com/ja-jp/aspnet/core/security/authentication/identity?view=aspnetcore-2.2&tabs=visual-studio)
[Asp.net Authorize](https://docs.microsoft.com/ja-jp/aspnet/core/security/authorization/simple?view=aspnetcore-2.2)
[ログについて](https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/logging/?view=aspnetcore-2.2)
[Nlog](https://mslgt.hatenablog.com/entry/2018/09/06/044014) ... Nlogのインストール後にVisual Studio の再起動をしないとNugetパッケージが認識されなかった。
[log4net vs nlog](https://blog.elmah.io/nlog-vs-log4net/)

### asp.net core 事例でおもしろそうなものメモ

[ASP.NET CoreとVue.jsとHTTP Streamingでオンラインゲーム作ってみたおはなし](https://qiita.com/askyq/items/89c28d234723b9bfd3c9)


### その他
[画面操作などをGIFで録画できる「ScreenToGif」を利用して直感的に伝える](https://nelog.jp/screen-to-gif)