Working with Static Files - 日本語意訳

- 2017/04/09(Sun) 時点の情報に基づいています
- 公式ドキュメント：[Introduction to working with static files in ASP.NET Core](https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/static-files)

# ASP.NET Core での 静的ファイルの扱い 概要


## 静的ファイルの提供

静的ファイルは通常 `web root`（*\<content-root>/wwwroot*）フォルダに配置されます。詳細については [ASP.NET Core 入門](../index.md) の「Content root と Web root」を参照してください。開発中は `web root` が見つかるように、Content root をカレントディレクトリに指定するのが一般的です。

```csharp:C#
public static void Main(string[] args)
{
    var host = new WebHostBuilder()
        .UseKestrel()
        .UseContentRoot(Directory.GetCurrentDirectory())
        .UseIISIntegration()
        .UseStartup<Startup>()
        .Build();

    host.Run();
}
```

静的ファイルは、`web root` 配下の任意のフォルダに配置し、そのルートからの相対パスでアクセスすることができます。例えば、Visual Studio でデフォルト Web アプリケーションプロジェクトを作成すると、*wwwroot* フォルダ配下に *css*、 *images*、 *js* といったフォルダが作成されます。*images* サブフォルダ内の画像にアクセスするための URI は以下のようになります：

* `http://<app>/images/<imageFileName>`
* `http://localhost:9189/images/banner3.svg`

静的ファイルを提供するためには、[Middleware](http://qiita.com/tkiryu/items/211d2b2f27af5dec5b52) を構成して、静的ファイルをパイプラインに追加しなくてはなりません。Nuget で *Microsoft.AspNetCore.StaticFiles* パッケージの参照をプロジェクトに追加し、`Startup.Configure` 内で
 `UseStaticFiles` 拡張メソッドを実行することで、Static file Middleware を構成することができます：

```csharp:C#
public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles();
}
```

`app.UseStaticFiles();` は、`web root`（デフォルトで *wwwroot*）内にある静的ファイルを提供可能にします。後ほど、`UseStaticFiles` メソッドを使って他のディレクトリコンテンツを提供可能にする方法を示します。

> [!注意]
> `web root` のデフォルトは *wwwroot* ディレクトリですが、`UseWebRoot` メソッドを使用して `web root` ディレクトリを変更することができます。

提供したい静的ファイルが `web root` の外部にあるようなプロジェクト階層があるとします。例えば：

* wwwroot
  * css
  * images
  * ...
* MyStaticFiles
  * test.png

 *test.png* へアクセスするためには、Static files Middleware を次のように構成します：

```csharp
public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles(); // For the wwwroot folder

    app.UseStaticFiles(new StaticFileOptions()
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), @"MyStaticFiles")),
        RequestPath = new PathString("/StaticFiles")
    });
}
```

`http://<app>/StaticFiles/test.png` へリクエストすることで *test.png* ファイルが提供されます。

`StaticFileOptions()` はレスポンスヘッダーを設定できます。例えば、以下のコードは *wwwroot* フォルダから静的ファイルを提供するよう設定し、`Cache-Control` ヘッダーを設定して10分間（600秒）キャッシュ可能にしています：

```csharp
public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles(new StaticFileOptions()
    {
        OnPrepareResponse = ctx =>
        {
            ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=600");
        }
    });
}
```

![Response headers showing the Cache-Control header has been added](https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/static-files/_static/add-header.png)


## 静的ファイルの認可

Static file Middleware は認可のチェックを**行いません**。*wwwroot* 配下のファイルを含む、Static file Middleware によって提供されるファイルは全て公開されます。認可に基づいてファイルを提供するには：

* *wwwroot* や Static file Middleware がアクセスできるディレクトリの外部にファイルを配置し、**かつ**

* コントローラーアクションを通してファイルを提供するようにし、認可が適用される `FileResult` を返すようにします。

## ディレクトリ参照を有効にする

ディレクトリ参照は、ユーザーに指定されたディレクトリ内のディレクトリとファイルのリストを参照可能にします。セキュリティの理由（[検討事項](#検討事項)を参照）からディレクトリ参照はデフォルトで無効にされています。ディレクトリ参照を有効にするには `Startup.Configure`メソッド内で `UseDirectoryBrowser` 拡張メソッドを実行してください：

```csharp:C#
public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles(); // For the wwwroot folder

    app.UseStaticFiles(new StaticFileOptions()
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), @"wwwroot", "images")),
        RequestPath = new PathString("/MyImages")
    });

    app.UseDirectoryBrowser(new DirectoryBrowserOptions()
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), @"wwwroot", "images")),
        RequestPath = new PathString("/MyImages")
    });
}
```

また、`Startup.ConfigureServices` メソッド内で `AddDirectoryBrowser` 拡張メソッドを実行して必要な Service を追加してください：

```csharp:C#
public void ConfigureServices(IServiceCollection services)
{
    services.AddDirectoryBrowser();
}
```

上記のコードは *wwwroot/images* フォルダへのディレクトリ参照を許可します。URL http://\<app>/MyImages で参照でき、各ファイルやフォルダへのリンクは以下のとおりです：

![directory browsing](https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/static-files/_static/dir-browse.png)

ディレクトリ参照を有効にした際のセキュリティリスクについては [検討事項](#検討事項) を参照してください。

2つの `app.UseStaticFiles` の呼び出しに注目してください。1つ目は *wwwroot* フォルダ内の CSS、images、JavaScript ファイルを提供し、2つ目は URL http://\<app>/MyImages で *wwwroot/images* フォルダへのディレクトリ参照を許可します：

```csharp:C#
public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles(); // For the wwwroot folder

    app.UseStaticFiles(new StaticFileOptions()
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), @"wwwroot", "images")),
        RequestPath = new PathString("/MyImages")
    });

    app.UseDirectoryBrowser(new DirectoryBrowserOptions()
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), @"wwwroot", "images")),
        RequestPath = new PathString("/MyImages")
    });
}
```


## デフォルトドキュメントの提供

デフォルトのホームページを設定することで、サイト訪問者にサイトを開始する場所を提供します。ユーザーが URI を完全指定しなくともデフォルトページが提供されるようにするには、次のように `Startup.Configure` 内で `UseDefaultFiles` 拡張メソッドを実行してください。

```csharp:C#
public void Configure(IApplicationBuilder app)
{
    app.UseDefaultFiles();
    app.UseStaticFiles();
}
```

> [!注意]
> デフォルトファイルを提供するためには、`UseDefaultFiles` メソッドは `UseStaticFiles` メソッドの前に実行しなければなりません。`UseDefaultFiles` は URL 書き換えであり、実際にファイルを提供しているわけではありません。ファイルを提供するためには、Static file Middleware (`UseStaticFiles`) を有効化しなければなりません。

`UseDefaultFiles` を使用すると、フォルダへのリクエストが行われると次のファイルが検索されます：

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

まるでリクエストが完全指定された URI であるかのように、リストから見つかった最初のファイルが提供されます（ブラウザの URL には元々リクエストされた URI が表示され続けます）。

次のコードは、デフォルトのファイル名を *mydefault.html* に変更する方法を示しています。

```csharp:C#
public void Configure(IApplicationBuilder app)
{
    // Serve my app-specific default file, if present.
    DefaultFilesOptions options = new DefaultFilesOptions();
    options.DefaultFileNames.Clear();
    options.DefaultFileNames.Add("mydefault.html");
    app.UseDefaultFiles(options);
    app.UseStaticFiles();
}
```


## UseFileServer

`UseFileServer` は、`UseStaticFiles`、 `UseDefaultFiles`、 `UseDirectoryBrowser` の機能を兼ね備えています。

次のコードは、静的ファイルとデフォルトファイルの提供を有効化しますが、ディレクトリ参照は許可しません：

```csharp:C#
app.UseFileServer();
   ```

次のコードは、静的ファイル、デフォルトファイル、ディレクトリ参照を有効化します：

```csharp:C#
app.UseFileServer(enableDirectoryBrowsing: true);
```

ディレクトリ参照を有効化した際のセキュリティリスクについては [検討事項](#検討事項) を参照してください。`UseStaticFiles`、`UseDefaultFiles`、および`UseDirectoryBrowser` と同様に、Web root の外部に存在するファイルを提供したい場合は、FileServerOptionsオブジェクトをインスタンス化して構成し、UseFileServer のパラメータとして渡してください。例えば、次のようなディレクトリ階層を持つ Web アプリケーションを考えてみてください：

* wwwroot
  * css
  * images
  * ...
* MyStaticFiles
  * test.png
  * default.html

上記のディレクトリ階層で、`MyStaticFiles` ディレクトリへの 静的ファイル、デフォルトファイル、ディレクトリ参照を有効にしたいとします。次のコードスニペットのように、`FileServerOptions` を設定するだけで実現できます。

```csharp:C#
public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles(); // For the wwwroot folder

    app.UseFileServer(new FileServerOptions()
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), @"MyStaticFiles")),
        RequestPath = new PathString("/StaticFiles"),
        EnableDirectoryBrowsing = true
    });
}
```

もし `EnableDirectoryBrowsing` を  `true` にセットした場合、`Startup.ConfigureServices`の中で `AddDirectoryBrowser` 拡張メソッドを実行する必要があります：

```csharp:C#
public void ConfigureServices(IServiceCollection services)
{
    services.AddDirectoryBrowser();
}
```

上記のディレクトリ階層とコードを使用すると、以下のようになります：

| URI            |                             Response  |
| ------- | ------|
| `http://<app>/StaticFiles/test.png`    |      MyStaticFiles/test.png |
| `http://<app>/StaticFiles`              |     MyStaticFiles/default.html |

もし *MyStaticFiles* ディレクトリ内に デフォルトファイルがなければ、http://\<app>/StaticFiles はクリック可能なディレクトリのリストを返します：

![Static files list](https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/static-files/_static/db2.png)

> [!注意]
> `UseDefaultFiles` と `UseDirectoryBrowser` は http://\<app>/StaticFiles という URL を末尾のスラッシュなしで扱うので、http://\<app>/StaticFiles/ (末尾にスラッシュ付き)へのクライアント側のリダイレクトに問題を引き起こします。末尾にスラッシュなしの相対 URL は不正となるでしょう。

### FileExtensionContentTypeProvider

`FileExtensionContentTypeProvider` クラスは、ファイル拡張子と コンテンツの MIME タイプをマッピングするためのコレクションを持っています。次のサンプルでは、いくつかのファイル拡張子が既知の MIME タイプに登録されており、".rtf" は置き換えられ、".mp4" は削除されています。

```csharp:C#
public void Configure(IApplicationBuilder app)
{
    // Set up custom content types -associating file extension to MIME type
    var provider = new FileExtensionContentTypeProvider();
    // Add new mappings
    provider.Mappings[".myapp"] = "application/x-msdownload";
    provider.Mappings[".htm3"] = "text/html";
    provider.Mappings[".image"] = "image/png";
    // Replace an existing mapping
    provider.Mappings[".rtf"] = "application/x-msdownload";
    // Remove MP4 videos.
    provider.Mappings.Remove(".mp4");

    app.UseStaticFiles(new StaticFileOptions()
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), @"wwwroot", "images")),
        RequestPath = new PathString("/MyImages"),
        ContentTypeProvider = provider
    });

    app.UseDirectoryBrowser(new DirectoryBrowserOptions()
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), @"wwwroot", "images")),
        RequestPath = new PathString("/MyImages")
    });
}
```

[MIME コンテンツタイプ](http://www.iana.org/assignments/media-types/media-types.xhtml) を参照してください。

## 非標準コンテンツタイプ

Static file middleware はおよそ 400 の既知のファイルコンテンツタイプを認識します。もしユーザーが不明なコンテンツタイプのファイルをリクエストした場合、Static file middleware は HTTP 404 (Not found) レスポンスを返します。もしディレクトリ参照が有効な場合、そのファイルへのリンクは表示されますが、そのリンクの URI へアクセスは HTTP 404 エラーを返します。

次のコードは、不明なコンテンツタイプの提供を有効にし、不明なファイルを画像として描画します。

```csharp:C#
public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles(new StaticFileOptions()
    {
        ServeUnknownFileTypes = true,
        DefaultContentType = "image/png"
    });
}
```

上記のコードで、不明なコンテンツタイプのファイルへのリクエストを画像として返すようになります。

>[!警告]
>  `ServeUnknownFileTypes` の有効化はセキュリティリスクであり、使用することはお勧めしません。`FileExtensionContentTypeProvider`（後述）は、標準的でない拡張子をもつファイルを提供するためのより安全な代替手段を提供します。

### 検討事項

>[!警告]
> `UseDirectoryBrowser` と `UseStaticFiles` は機密漏洩の可能性があります。本番環境ではディレクトリ参照を有効化**しない**ことをお勧めします。`UseStaticFiles` や `UseDirectoryBrowser` を使って有効化したディレクトリは、ディレクトリ全体とサブディレクトリ全てがアクセス可能になるので、注意してください。*\<content root>/wwwroot* などの独自のディレクトリに公開コンテンツを保存し、アプリケーションビューや設定ファイルなどから分離しておくことをお勧めします。

* `UseDirectoryBrowser` および `UseStaticFiles` で公開されるコンテンツの URL は、その基となるファイルシステムの大文字小文字の区別および文字制限に左右されます。例えば、Windows は大文字小文字を区別しませんが、Mac と Linux は区別します。

* IIS でホストされる ASP.NET Core アプリケーションは、ASP.NET Core モジュールを使用して、静的ファイルへのリクエストを含むすべてのリクエストをアプリケーションに転送します。IIS 静的ファイルハンドラーは使用されることはありません。なぜなら、ASP.NET Core モジュールが先にリクエストを処理してしまうため、IIS 静的ファイルハンドラーがリクエストを処理するチャンスがないからです。

* IIS 静的ファイルハンドラーを(サーバーや Web サイトレベルで)削除するには：

     * **モジュール**機能に移動し

     * リストの中から **StaticFileModule** を選択し

     * **操作**サイドバー内の**削除**をタップします

>[!警告]
> もし IIS 静的ファイルハンドラーが有効で、**かつ**、ASP.NET Core モジュール (ANCM) が正しく構成されていない場合(例えば web.config がデプロイされていないなど)、静的ファイルが提供されてしまいます。

* （C# と Razor を含む）コードファイルは、アプリケーションプロジェクトの Web root（デフォルトでは wwwroot）の外側に配置すべきです。 こうすることで、アプリケーションのクライアント側のコンテンツとサーバー側のソースコードが明確に分離され、サーバー側のコードの漏洩を防ぎます。

## その他のリソース

* [Middleware](http://qiita.com/tkiryu/items/211d2b2f27af5dec5b52)

* [Introduction to ASP.NET Core](../index.md)