ASP.NET Coreについて一から勉強してみる。①

#1.はじめに
こんにちは、@yuzen-ykです。

##誰？
Yoshiki Kaneko(@yuzen-yk)と申します。

今年から新卒社会人(開発エンジニア)になりました。現在研修でいろいろなことを勉強している最中です。
開発言語は**C#**、フレームワークは**.NET Core**をメインに学んでいます。

##なぜこの記事を書こうと思ったか
研修でASP.NET Coreについて学んでいて、Visual Studioのプロジェクトテンプレートを使って簡単なWebアプリやWeb APIを作っているのですが、知識の穴(普段気にしないけど、Program.csのこのメソッドの役割は？とか)が自分の中にはたくさんあるため、それを解消する目的で書くことにしました。

##注意点
勉強中の身なのでもしかしたら間違ったことを書いてることが大いにあり得ます。大目に見てください。

#2.プロジェクトの基礎
とりあえずVisual Studioを起動して、ASP.NET Coreの空のテンプレートを開いてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1751890/d06cbb36-7ec9-005b-fa9c-c05bdc520f51.png)

ソリューションエクスプローラはこうなっていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1751890/7bd72c08-6967-3863-cd05-7d83d2f0a931.png)

ASP.NET Coreには根幹となる二つのファイル(**Program.cs**と**Startup.cs**)があります。今回はそれを見ていきます。

##Program.cs
まず一つが**Program.cs**です。
デフォルトでこんな感じのコードが記述されています。

```C#:Program.cs
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace WebApplication1
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}
```

###Mainメソッド
C#でプログラムを書いている人にはおなじみのMainメソッドです。
プログラムを実行するとまずはここから処理が始まります。

```C#
public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }
```

CreateHostBuilderというメソッドが書かれています。
メソッドの戻り値からBuildメソッドを呼び出し、さらにRunメソッドを呼び出しています。
なんのこっちゃ。

###CreateHostBuilderメソッド

```C#
public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
```

CreateHostBuilderメソッドには戻り値としてIHostBuilderが設定されていました。
このインターフェースが実装されているのはHostBuilderクラスです。HostBuilderクラスの役割は、**Webホスト**(Webサーバともいう)を構築するというものになります。
Webホストって何？って人は以下のサイトがわかりやすいかと思われます。正直僕も詳しくわかってません。とりあえずWebアプリ作成する上で必要なものだと認識。
[「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典 ホスト(Host)](https://wa3.i-3-i.info/word1336.html)

このWebホストの機能ですが、Hostという名前のクラスにすべて実装されています。

HostBuilderクラス内には**Build**というメソッドがあり、こいつが上述のHostクラスのインスタンスを生成します。その後、Hostクラス内の**Run**メソッドを呼び出してWebホストの機能が実行されます。

###Hostインスタンスの生成
CreateHostBuilderメソッドの中身を見ていきます。

```C#
Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
```

HostクラスのCreateDefaultBuilderというメソッドが呼び出されています。こいつの役割はデフォルトのHostBuilderインスタンスを生成するというところにあります。

その後のConfigureWebHostDefaultsメソッドは、Hostクラスのインスタンスをデフォルトで生成するものです。このメソッドの引数にはラムダ式が書かれており、引数webBuilderにはIWebHostBuilderというインターフェイス(正確にはWebHostBuilderクラスのインスタンス)が渡されるようです。

ラムダ式の内部ではUseStartupメソッドが呼び出されています。これはStartupクラスの方でホストを起動した際の初期化処理を行うようにしています。

###まとめ
**「Startupで初期化処理を行う形でHostインスタンスを生成し、Webホストの構築を行う」**というのがProgram.csの役割っぽいです、多分。

##Startup.cs
「じゃあStartup.csって何」って感じなのでStartup.csも見ていきます。

Startup.csにはこんな記述がされています。

```C#
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace WebApplication1
{
    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });
            });
        }
    }
}
```

Startup.csには二つの重要なメソッドが存在します。一つずつ見ていきましょう。

###ConfigureServicesメソッド

```C#
public void ConfigureServices(IServiceCollection services)
        {
        }
```

このメソッドでは**サービスの登録**を行います。
サービスってなんぞやって感じですが、ASP.NET Coreでは「サービス」と呼ばれる形で外部からインストールしてきたプログラムパッケージを組み込んで機能の拡張を行うことができます。その際、サービスの登録をここに記述する形で行います。
デフォルトでは何も組み込んでいないので何も書かれていません。

###Configureメソッド

```C#
 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });
            });
        }
```

このメソッドでは**ミドルウェアの登録**を行います。

ASP.NET Coreでは、アプリケーションがHTTPで呼び出されてからレスポンスを返すまでの応答を、ミドルウェアと呼ばれるプログラムを組み込むことで機能を拡張することができます。
デフォルトではメソッドの引数に次の二つが用意されています。

・IApplicationBuilder
簡単に言えば**呼び出し→応答の流れそのもの(パイプラインともいう)**を扱う(形作る？)ものです。

・IWebHostEnvironment
Webホストの実行環境に関するクラスです。


###例外ページ設定

```C#
if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
```

if文から始まるこいつは、作成しているプロジェクトが**開発環境**か**本番環境**かでどのエラーページを表示するかというのを表しています。
開発環境の場合は開発者向けのエラーページが出るように設定されていますね。

###ルーティング設定

```C#
app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });
            });
```

**UseRouting**はルーティング機能をONにします。
ルーティングは**「特定のアドレスにアクセスしたときに特定の処理を実行させる」**という働きを持っています。

こいつがONになっていると、そのあとの処理が行われます。
**UseEndPoint**はエンドポイント(呼び出し→応答の中で最後に呼び出されるミドルウェア)を設定します。その後、MapGetメソッドで第1引数に指定されたパスにアクセスし、ラムダ式の後に書かれているcontext.Response.WriteAsyncというメソッドの引数に指定された文字列をWebページ上に表示します。

実行してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1751890/dda009bd-df96-8fb2-6f98-55a4d478bf5c.png)

context.Response.WriteAsyncの引数に指定された「Hello World!」という文字列が表示されました。

#3．おわりに
ASP.NET Coreの根幹となる2つのファイルについて勉強してみました。
研修でもある程度聞いた内容ではありましたが、研修にプラスして自分で深堀りしてみて、得られたものをこういう媒体にアウトプットすることは大事だなと思いました。かなり理解が深まったような気がします。