ASP.NET Core MVC WWWROOT以外の静的ファイル


ASP.NET Core 2.1～5.0までは同じみたい。
実際にプログラムで確認したのはASP.NET Core 3.1です。

#課題
#####システムの構成はこうなります

* 動的なシステム部分（ASP.NET Core MVCで構築）
* 静的な既定ドキュメント「展示、説明」など（ログインかもしくは申込などリンクで動的な部分と繋がる）

<details><summary>「wwwroot」以外の場所から静的な部分を提供する、理由は展開して確認</summary><div>
　　上記二つの部分、それぞれ独自のcss,javascript,imageが存在します。
　　基本的にウエブシステムを構築する際は「wwwroot」に静的内容とcss,javascript,imageなどを配置することになります。でも今回の場合は全部一ヶ所に配置すると、色々と混乱し易くなります。
　　そもそも上の二つの部分はそれぞれ単独に動けるから、二つのシステムと考えても全然問題ありませんし、一ヶ所に配置するのもどうかと思う。
　　開発の観点から見ると、静的の部分は基本的にデザイナーかデザイン会社にお願いして、動的な部分と並行して開発することになりますので。
　　以上の原因で「wwwroot」以外の場所から静的な部分を提供するほうが良い。
</div></details>

#実装

```C#:Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    //前略．．．
    //wwwrootに対して静的コンテンツサービスを登録
    app.UseStaticFiles();
    //wwwroot以外に静的コンテンツサービスを登録
    app.UseFileServer(new FileServerOptions
    {
        //登録するフォルダーを指定、絶対パスを設定する必要がある
        FileProvider = new PhysicalFileProvider("C:\\StaticContent"),
    });
    //後略．．．
}

```

そうすることで「https://<ホスト名>」をアクセスした場合、「C:\\StaticContent\\」の中で以下のファイルを検索し

* default.htm
* default.html
* index.htm
* index.html

最初に見つけたファイルをクライアントへ返す。
「wwwroot」のなかに「index.html」を配置しても、検索されることはない。
静的な既定ドキュメントを提供するには「UseDefaultFiles」でサービスを登録する必要があります。
静的なファイルに関するサービスは以下四つがある

* UseStaticFiles
* UseDefaultFiles
* UseDirectoryBrowser
* UseFileServer

この四つのサービスに関して、詳しく見ていきましょう。

# UseStaticFiles

静的ファイルを提供するサービスです。

```C#:Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    //前略．．．
    //パラメータなしの場合は「wwwroot」フォルダー及びサブフォルダの全ファイルを静的コンテンツとして提供する
    //デフォルトでは認証と認可ミドルウェアの前に登録されているので、「wwwroot」の静的コンテンツをアクセスする際は認証と認可は不要
    app.UseStaticFiles();
    //後略．．．
    app.UseAuthentication();
    app.UseAuthorization();
    //後略．．．
}
```

UseStaticFilesがパラメータ無しの場合は「wwwroot」を指しているので、最初から入っている静的ファイルをアクセスできる理由はここにあります。

```C#:Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    //前略．．．
    //パラメータなしの場合は「wwwroot」フォルダー及びサブフォルダの全ファイルを静的コンテンツとして提供する
    app.UseStaticFiles();
    //「wwwroot」以外に「StaticContent」フォルダーも静的ファイルを提供する
    //app.UseStaticFiles();の呼び出しがないと「wwwroot」へのアクセスができなくなる
    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider("C:\\StaticContent")
    });
    //後略．．．
    app.UseAuthentication();
    app.UseAuthorization();
    //後略．．．
}
```

#UseDefaultFiles
既定のドキュメントの提供

```C#:Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    //前略．．．
    app.UseDefaultFiles();
    app.UseStaticFiles();
    //「wwwroot」以外に「StaticContent」フォルダーも静的ファイルを提供する
    //app.UseStaticFiles();の呼び出しがないと「wwwroot」へのアクセスができなくなる
    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider("C:\\StaticContent")
    });
    //後略．．．
    app.UseAuthentication();
    app.UseAuthorization();
    //後略．．．
}
```

UseDefaultFilesは「wwwroot」にある以下のファイルを既定ドキュメントとして提供

* default.htm
* default.html
* index.htm
* index.html

上記四つ以外のファイルを既定ドキュメントにするには以下のようにパラメータを設定する必要がある

```C#:Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    //前略．．．
    //既定ドキュメントの設定
    DefaultFilesOptions defaultFilesOptions = new DefaultFilesOptions();
    //デフォルトのファイル名設定をクリア
    defaultFilesOptions.DefaultFileNames.Clear();
    //既定ドキュメント名を指定
    defaultFilesOptions.DefaultFileNames.Add("myIndex.html");
    app.UseDefaultFiles(defaultFilesOptions);

    app.UseStaticFiles();
    //「wwwroot」以外に「StaticContent」フォルダーも静的ファイルを提供する
    //app.UseStaticFiles();の呼び出しがないと「wwwroot」へのアクセスができなくなる
    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider("C:\\StaticContent")
    });
    //後略．．．
    app.UseAuthentication();
    app.UseAuthorization();
    //後略．．．
}
```

UseDefaultFilesが影響できるのは「wwwroot」フォルダーのみ、独自に新規で追加した静的コンテンツフォルダーには影響しない

#UseDirectoryBrowser
サーバー上に指定したディレクトリ内のディレクトリを一覧表示にする、だがセキュリティー上の問題があるため、利用を避けるべき。デフォルトは無効になっている。

```C#:Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    //前略．．．
    //EnableDirectoryBrowsing = trueの時、下記を呼び出す必要がある
    services.AddDirectoryBrowser();
    //後略．．．
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    //前略．．．
    app.UseStaticFiles();
    //「wwwroot」以外に「StaticContent」フォルダーも静的ファイルを提供する
    //app.UseStaticFiles();の呼び出しがないと「wwwroot」へのアクセスができなくなる
    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider("C:\\StaticContent")
    });
    //ディレクトリ参照を起用する
    app.UseDirectoryBrowser(new DirectoryBrowserOptions
    {
        //ディレクトリ参照の対象フォルダー
        FileProvider = new PhysicalFileProvider("C:\\StaticContent"),
        //ディレクトリ参照するためのURL相対パス
        //https://<hostname>/DirectoryBrowser
        RequestPath = "/DirectoryBrowser"
    });
    //略．．．
    app.UseAuthentication();
    app.UseAuthorization();
    //後略．．．
}
```

「https://<ホスト名>/DirectoryBrowser」でアクセスすると、「C:\\StaticContent」内のディレクトリを一覧で表示される


#UseFileServer
UseStaticFiles、UseDefaultFiles、UseDirectoryBrowser の機能を兼ね備えているのがUseFileServerです

```C#:Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    //前略．．．
    //EnableDirectoryBrowsing = trueの時、下記を呼び出す必要がある
    services.AddDirectoryBrowser();
    //後略．．．
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    //前略．．．
    app.UseStaticFiles();
    //「wwwroot」以外に「StaticContent」フォルダーも静的ファイルを提供する
    app.UseFileServer(new FileServerOptions
    {
        //静的ファイルを提供する対象フォルダー
        FileProvider = new PhysicalFileProvider("C:\\StaticContent"),
        //デフォルトがtrue:デフォルトファイルを起用
        EnableDefaultFiles = true,
        //デフォルトがfalse:ディレクトリブラウザ禁止
        EnableDirectoryBrowsing = true
        //静的コンテンツをアクセスするための相対パス
        RequestPath = "/StaticFiles",

    });
    //略．．．
    app.UseAuthentication();
    app.UseAuthorization();
    //後略．．．
}
```

#まとめ
UseStaticFilesとUseDefaultFilesの既定では下記のFileProviderを提供している

```C#
FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "wwwroot"));
```

だからパラメータ無しの場合の操作対象が「wwwroot」となっている。
でも既定の「wwwroot」を変更することは可能
変更方法は

```C#:Program.cs
public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            //ここで既定の「wwwroot」を指定したフォルダーに変更できる
            webBuilder.UseStartup<Startup>().UseWebRoot("C:\\NewWebRoot");
        });

```