お茶漬けびより

"あなたに教わったことを、噛んでいるのですよ" 五等分の花嫁 7巻 「最後の試験が五月の場合」より

CLI で asp.net core の環境を構築する

NET Core CLIVSCodeASP.NET Core の環境を作っていきます。

目標は、以下の手順3 まで行うことです。

docs.microsoft.com

docs.microsoft.com

上記は、Visual Studio を使っていますが、ここでは、NET Core CLIVSCode のみです。 私の環境は Mac ですが、WindowsLinux でも問題ないと思います(Windows の方が問題ないかも……)。

.NET Core SDK のインストール

公式サイトからパッケージを落としてインストールします。以下のURL先で Download .NET Core SDK をクリックしてパッケージを落とします。

dotnet.microsoft.com

インストールしたら、ターミナルを立ち上げて dotnet --version で動作するか確認します。

$dotnet --version
3.1.102

プロジェクトの作成をする

プロジェクトの作成は CLI で行います。dotnet new でプロジェクトの作成が出来ますが、プロジェクトの種類は多数あるので、一度 --help でどんなものがあるか確認してみましょう。

dotnet new --help を叩くと私の環境では、以下のように表示されました(途中に表示されるオプションは省略しています)。

Templates                                         Short Name               Language          Tags
----------------------------------------------------------------------------------------------------------------------------------
Console Application                               console                  [C#], F#, VB      Common/Console
Class library                                     classlib                 [C#], F#, VB      Common/Library
WPF Application                                   wpf                      [C#]              Common/WPF
WPF Class library                                 wpflib                   [C#]              Common/WPF
WPF Custom Control Library                        wpfcustomcontrollib      [C#]              Common/WPF
WPF User Control Library                          wpfusercontrollib        [C#]              Common/WPF
Windows Forms (WinForms) Application              winforms                 [C#]              Common/WinForms
Windows Forms (WinForms) Class library            winformslib              [C#]              Common/WinForms
Worker Service                                    worker                   [C#]              Common/Worker/Web
Unit Test Project                                 mstest                   [C#], F#, VB      Test/MSTest
NUnit 3 Test Project                              nunit                    [C#], F#, VB      Test/NUnit
NUnit 3 Test Item                                 nunit-test               [C#], F#, VB      Test/NUnit
xUnit Test Project                                xunit                    [C#], F#, VB      Test/xUnit
Razor Component                                   razorcomponent           [C#]              Web/ASP.NET
Razor Page                                        page                     [C#]              Web/ASP.NET
MVC ViewImports                                   viewimports              [C#]              Web/ASP.NET
MVC ViewStart                                     viewstart                [C#]              Web/ASP.NET
Blazor Server App                                 blazorserver             [C#]              Web/Blazor
ASP.NET Core Empty                                web                      [C#], F#          Web/Empty
ASP.NET Core Web App (Model-View-Controller)      mvc                      [C#], F#          Web/MVC
ASP.NET Core Web App                              webapp                   [C#]              Web/MVC/Razor Pages
ASP.NET Core with Angular                         angular                  [C#]              Web/MVC/SPA
ASP.NET Core with React.js                        react                    [C#]              Web/MVC/SPA
ASP.NET Core with React.js and Redux              reactredux               [C#]              Web/MVC/SPA
Razor Class Library                               razorclasslib            [C#]              Web/Razor/Library/Razor Class Library
ASP.NET Core Web API                              webapi                   [C#], F#          Web/WebAPI
ASP.NET Core gRPC Service                         grpc                     [C#]              Web/gRPC
dotnet gitignore file                             gitignore                                  Config
global.json file                                  globaljson                                 Config
NuGet Config                                      nugetconfig                                Config
Dotnet local tool manifest file                   tool-manifest                              Config
Web Config                                        webconfig                                  Config
Solution File                                     sln                                        Solution
Protocol Buffer File                              proto                                      Web/gRPC

二列目に Short Name があります。これを引数に指定します。ちなみにプロジェクトだけでなく、一部のファイルは new で作成できます。上記は、ファイルのテンプレートも混ざっているので見辛いです。プロジェクトだけに絞りたいときは、dotnet new --type project を実行します。

Templates                                         Short Name               Language          Tags
----------------------------------------------------------------------------------------------------------------------------------
Console Application                               console                  [C#], F#, VB      Common/Console
Class library                                     classlib                 [C#], F#, VB      Common/Library
WPF Application                                   wpf                      [C#]              Common/WPF
WPF Class library                                 wpflib                   [C#]              Common/WPF
WPF Custom Control Library                        wpfcustomcontrollib      [C#]              Common/WPF
WPF User Control Library                          wpfusercontrollib        [C#]              Common/WPF
Windows Forms (WinForms) Application              winforms                 [C#]              Common/WinForms
Windows Forms (WinForms) Class library            winformslib              [C#]              Common/WinForms
Worker Service                                    worker                   [C#]              Common/Worker/Web
Unit Test Project                                 mstest                   [C#], F#, VB      Test/MSTest
NUnit 3 Test Project                              nunit                    [C#], F#, VB      Test/NUnit
xUnit Test Project                                xunit                    [C#], F#, VB      Test/xUnit
Blazor Server App                                 blazorserver             [C#]              Web/Blazor
ASP.NET Core Empty                                web                      [C#], F#          Web/Empty
ASP.NET Core Web App (Model-View-Controller)      mvc                      [C#], F#          Web/MVC
ASP.NET Core Web App                              webapp                   [C#]              Web/MVC/Razor Pages
ASP.NET Core with Angular                         angular                  [C#]              Web/MVC/SPA
ASP.NET Core with React.js                        react                    [C#]              Web/MVC/SPA
ASP.NET Core with React.js and Redux              reactredux               [C#]              Web/MVC/SPA
Razor Class Library                               razorclasslib            [C#]              Web/Razor/Library/Razor Class Library
ASP.NET Core Web API                              webapi                   [C#], F#          Web/WebAPI
ASP.NET Core gRPC Service                         grpc                     [C#]              Web/gRPC
Solution File                                     sln                                        Solution

project の他に、item, other などがあります。item はファイルのテンプレートっぽいです。

今回作成するプロジェクトは、ASP.NET Core なので、webapp を指定します。dotnet new webapp -o FirstApp で実行します。-o は出力先のディレクトリで、存在しない場合は自動で作成されます。ディレクトリとプロジェクト名を別にしたい場合は、-n でプロジェクト名を指定します。

プロジェクトのテンプレートを見ると Angular や React などがありますが、これはクライアント側の構成です。今回の webapp では、Blazor になります。Blazor については、

docs.microsoft.com

を読めば何となく分かると思います。Blazor の良し悪しについては、

qiita.com

で判断できると思います。良し悪しというより自分に向いているか向いていないのかですね。今回は、クライアント側ではなくサーバ側の ASP.NET に慣れることが目的なので、Blazor のままで進めます。

ここでサーバを実行できる環境が整ったので、一度、動作確認してみましょう。プロジェクト直下で、dotnet run と実行します。localhost:5001localhost:5000 にアクセスするとWebアプリが表示されると思います。

動作確認をしたので画面の内容を編集して、結果が反映されるか確認してみましょう。

プロジェクト直下で code . と実行し、VSCode を開きます。index.cshtml を開き、<div> の中身を以下のように書き換えます。@Model.Time が Blazor 特有の変数みたいです。

<div class="text-center">
    <h2>It's @Model.Time right now on ther server!</h2>
</div>

次に、@Model.Time の値を初期化する処理を追加します。index.cshtml.cs を開きます。OnGet メソッドを以下のように変更します。また、変数 Time を追加します。

public string Time { get; set; }
public void OnGet()
{
    Time = DateTime.Today.ToShortTimeString();
}

サーバを実行し直すと、反映されていることが分かると思います。時間は、常に 0:00 です。これは、Today の返す値が、日付 0:00 と返すためです。本当にそうなっているのかデバッグで確認してみましょう。

VSCodeデバッグ

VSCodeデバッグを開き(通常だと左側の虫のマーク)、VSCodelaunch.json を作成する機能を呼び出し、 .NET Core を選択しlaunch.json を作成します。

.NET Core Launch (web) を選択して、デバッグを開始します。Time = DateTime.Today.ToShortTimeString(); の箇所でブレークポイントを貼り、サイトにアクセスします。すると、ブレークポイントで止まると思います。デバッグしても起動に失敗する場合、ターミナル側でサーバを立ち上げっぱなしにしていないか確認してください。

ブレークポイントの位置では、まだ Time に値は入っていないので、null です。ステップを一つ進める(Step Over)と値が入り、0:00 になっているのが確認できます(Time にカーソルを当てると表示されます)。また、VSCode の下側に DEBUG CONSOLE が表示されていると思いますが、そこでコードを実行することができます。例えば、DateTime.Today と実行すると {2020/03/07 0:00:00} と表示されます(値は、日付によって変わります)。これを見ると 0:00 が表示される理由が分かりますね。

では、現在の時刻が表示されるように修正します。例えば、TodayNow に変更してみます。デバッグを起動している場合は、Restart のアイコンをクリックすれば起動しなおします。確認すると現在の時刻が表示されていると思います。

DB を追加する

DB を追加し、DB を操作する画面を追加します。まず、DB に追加する情報を持つモデルを作成します。今回は、Game というモデルにします。Models ディレクトリを作成し、その下で Game.cs を作成します。中身は、以下になります。

public class Game
{
    public int Id { get; set; }
    public string Title { get; set; }
    public int PublicationYear { get; set; }
    public int MinimumPlayers { get; set; }
    public int MaximumPlayers { get; set; }
}

次に、DBの環境を整えます。私は、C# .NET に詳しくないのでよく分かっていないのですが、 .NET では、 Entity Framework で DB を簡単に操作するようにするのが一般的みたいです。なので、この Entity Framework を使えるようにします。.NET Core では、 Entity Framework Core(EF Core) を使います。

.NET CLI では、フレームワークやライブラリをコマンドで追加できます。NuGet のパッケージを追加するときもコマンドを使います。EF Core を追加する場合、tool コマンドを使います。追加したツールの一覧は、dotnet tool list --global で確認出来ます。初めての場合は、何も追加されていないと思います。

EF Core を dotnet tool install --global dotnet-ef でインストールします。インストールが完了したら、再度一覧を表示して、追加されていることを確認します。私の環境では、以下のようになりました。

パッケージ ID                         バージョン      コマンド
-----------------------------------------------------------------------
dotnet-ef                        3.1.2      dotnet-ef

また、dotnet ef --version で使えるか確認します。

Entity Framework Core .NET Command-line Tools
3.1.2

さて、EF Core を追加しました。Visual Studio の場合は、テンプレートで DB を操作するページを作成できます(以下のURL先を参照)。

docs.microsoft.com

同じことをしたい場合、もう少し環境を整える必要があります。dotnet tool install -g dotnet-aspnet-codegenerator で EF に関するコードを作成してくれるコードジェネレータツールを追加します。追加したら、dotnet aspnet-codegenerator -h で動作確認します。といってもオプションに -h はないっぽいですが。

Blazor のページを Razor Page と呼ぶそうですが、この Razor Page を追加するには、次のコマンドで追加できます。ただ、現状はまだ失敗します。

dotnet aspnet-codegenerator razorpage -m Game -dc AppDbContext -outDir Pages/Games

aspnet-codegenerator ツールを使うには、以下のパッケージが必要です。

追加するときは、dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design のようにします。dotnet add package 追加したいパッケージ名です。

Microsoft.EntityFrameworkCore.SqlServer は、ツールを使うために必要です。Mac やおそらく Linux は、DBとして SqlServer は使えません(どうにかすれば使えるのかもしれませんが)。ですので、別途 DB のツールを追加する必要があります。今回は、 Microsoft.EntityFrameworkCore.InMemory を使います。

またNuget のパッケージですので、ここで追加したパッケージは、別のプロジェクトで必要なとき、同じようにパッケージを追加するコマンドを実行する必要があります。追加されているパッケージは、dotnet list package で確認できます。

上記3つを入れていると以下のように出力されるはずです。InMemory を追加している場合は、それも表示されているはずです。

プロジェクト 'FirstApp' に次のパッケージ参照が含まれています
   [netcoreapp3.1]:
   最上位レベル パッケージ                                            要求済み    解決済み
   > Microsoft.EntityFrameworkCore.SqlServer               3.1.2   3.1.2
   > Microsoft.EntityFrameworkCore.Tools                   3.1.2   3.1.2
   > Microsoft.VisualStudio.Web.CodeGeneration.Design      3.1.1   3.1.1

では、dotnet aspnet-codegenerator razorpage -m Game -dc AppDbContext -outDir Pages/Games を実行して、成功するか確認しましょう。成功した場合、以下のように出力されます。

Building project ...
Finding the generator 'razorpage'...
Running the generator 'razorpage'...
Generating a new DbContext class 'AppDbContext'
Attempting to compile the application in memory with the added DbContext.
Attempting to figure out the EntityFramework metadata for the model and DbContext: 'Game'
Added DbContext : '/Data/AppDbContext.cs'
Added Razor Page : /Pages/Games/Create.cshtml
Added PageModel : /Pages/Games/Create.cshtml.cs
Added Razor Page : /Pages/Games/Edit.cshtml
Added PageModel : /Pages/Games/Edit.cshtml.cs
Added Razor Page : /Pages/Games/Details.cshtml
Added PageModel : /Pages/Games/Details.cshtml.cs
Added Razor Page : /Pages/Games/Delete.cshtml
Added PageModel : /Pages/Games/Delete.cshtml.cs
Added Razor Page : /Pages/Games/Index.cshtml
Added PageModel : /Pages/Games/Index.cshtml.cs
RunTime 00:00:09.50

成功したら、Data ディレクトリが作成され、AppDbContext.cs が追加されていると思います。また、Pages/Games には、Create, Delete, Details, Edit, Index の cshtml, cs ファイルが追加されていると思います。

SqlServer ではなく、InMemory を使う場合

上記のジェネレータツールを実行すると SqlServer を使うようにコードが変更されています。ですので、これを使用したい DB に合わせる必要があります。

今回は、InMemory を使うため Startup.cs を開き、以下のように変更します。optionsUse...UseInMemoryDatabase に変えるだけです。

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();
    services.AddDbContext<AppDbContext>(options => options.UseInMemoryDatabase(Configuration.GetConnectionString("AppDbContext")));
}

以上です。

DB を操作するページを作成する

最後に Programs.cs を以下のように変更します。

...
using Microsoft.Extensions.DependencyInjection;

...

public static void Main(string[] args)
{
    var host = CreateHostBuilder(args).Build();
    using (var scope = host.Services.CreateScope()) {
        var services = scope.ServiceProvider;
        try
        {
            var context = services.GetRequiredService<AppDbContext>();
            context.Database.EnsureCreated();
        }
        catch (Exception ex)
        {
            var logger = services.GetRequiredService<ILogger<Program>>();
            logger.LogError(ex, "An error occurred creating the DB.");
        }
    }
    host.Run();
}

これで完了です。dotnet run で実行して、localhost:5000/Games にアクセスしてみてください。テーブルの追加や削除、編集の画面が出てくると思います。

参考

以下の文献を参考にしました(途中で挙げているものは抜いています)。

docs.microsoft.com

docs.microsoft.com

docs.microsoft.com

docs.microsoft.com

使用できる DB は、これを見ると分かります。

docs.microsoft.com

コマンドのドキュメントです。

docs.microsoft.com

docs.microsoft.com

より理解を深めるために読むと良さそうです(未読)。

docs.microsoft.com

NuGet について

docs.microsoft.com

おわりに

Android 開発の入門の息抜きに始めたときは、本当に VSCode だけで出来るか不安だったのですが、何とか最後まで行けました。コードジェネレータあたりで詰まりかけましたが……。どのツールも強力なので使いこなせると便利そうです。ただ、学習コスト高そうなので、自動化のような目的がないなら Visual Studio でいい気がします。

ASP.NET .NET Framework の知識がなさすぎて、中身のコードややってることを全然理解できていないので、暇があれば調べてみたいですね。ASP.NET 面白そうですし。

最後にこの手順を行った時のソースコードを載せておきます。

github.com