ASP.NET Core の静的ファイル

作成者: Rick Anderson および Kirk Larkin

HTML、CSS、画像、JavaScript などの静的ファイルは、既定では ASP.NET Core アプリにより直接クライアントに提供される資産です。

静的ファイルの提供

静的ファイルは、プロジェクトの Web ルート ディレクトリ内に格納されています。 既定のディレクトリは {content root}/wwwroot ですが、UseWebRoot メソッドを使用して変更できます。 詳細については、「コンテンツ ルート」および「Web ルート」を参照してください。

CreateBuilder メソッドでは、コンテンツのルートが現在のディレクトリに設定されます。

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

静的ファイルには、Web ルートに対する相対パスを使用してアクセスできます。 たとえば、Web アプリケーション プロジェクト テンプレートでは、wwwroot フォルダー内に次のいくつかのフォルダーが含まれています。

  • wwwroot
    • css
    • js
    • lib

wwwroot/images フォルダーを作成し、wwwroot/images/MyImage.jpg ファイルを追加する場合を考えてみます。 images フォルダー内のファイルにアクセスするための URI 形式は https://<hostname>/images/<image_file_name> です。 たとえば、https://localhost:5001/images/MyImage.jpg

Web ルート内のファイルの提供

既定の Web アプリ テンプレートでは、Program.cs 内で UseStaticFiles メソッドが呼び出されます。これにより、静的ファイルを提供できるようになります。

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

UseStaticFiles メソッドのパラメーターなしのオーバーロードによって、Web ルート内のファイルが提供可能とマークされます。 次のマークアップは、wwwroot/images/MyImage.jpg を参照します。

<img src="~/images/MyImage.jpg" class="img" alt="My image" />

上記のマークアップでは、チルダ文字 ~Web ルートを指します。

Web ルート外のファイルの提供

提供する静的ファイルが Web ルートの外にあるディレクトリ階層について考えます。

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • red-rose.jpg

静的ファイル ミドルウェアを次のように構成すると、要求で red-rose.jpg ファイルにアクセスできます。

using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles"
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

前述のコードでは、MyStaticFiles ディレクトリ階層は、StaticFiles URI セグメントでパブリックに公開されています。 https://<hostname>/StaticFiles/images/red-rose.jpg の要求は、red-rose.jpg ファイルを提供します。

次のマークアップは、MyStaticFiles/images/red-rose.jpg を参照します。

<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />

複数の場所からファイルを提供するには、「複数の場所からファイルを提供する」を参照してください。

HTTP 応答ヘッダーの設定

StaticFileOptions オブジェクトを使用すると、HTTP 応答ヘッダーを設定できます。 Web ルートから提供される静的ファイルの構成に加えて、次のコードで Cache-Control ヘッダーを設定します。

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

var cacheMaxAgeOneWeek = (60 * 60 * 24 * 7).ToString();
app.UseStaticFiles(new StaticFileOptions
{
    OnPrepareResponse = ctx =>
    {
        ctx.Context.Response.Headers.Append(
             "Cache-Control", $"public, max-age={cacheMaxAgeOneWeek}");
    }
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

上記のコードでは、静的ファイルをローカル キャッシュに 1 週間 (604800 秒) 公開します。

Response headers showing the Cache-Control header has been added V6

静的ファイルの承認

ASP.NET Core テンプレートでは、UseAuthorization を呼び出す前に UseStaticFiles が呼び出されます。 ほとんどのアプリがこのパターンに従います。 認可ミドルウェアの前に静的ファイル ミドルウェアが呼び出される場合:

  • 静的ファイルに対して認可チェックは実行されません。
  • 静的ファイル ミドルウェアによって提供される静的ファイル (wwwroot 下にあるものなど) には、パブリックにアクセスできます。

認可に基づいて静的ファイルを提供するには:

  • それらを wwwroot の外部に保存します。
  • UseAuthorization を呼び出した後に、パスを指定して UseStaticFiles を呼び出します。
  • フォールバック認可ポリシーを設定します。
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders;
using StaticFileAuth.Data;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();

builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
});

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles"
});

app.MapRazorPages();

app.Run();

上記のコードでは、フォールバック認可ポリシーによって "すべて" のユーザーを認証することが要求されます。 独自の認可要件を指定する、コントローラー、Razor Pages などのエンドポイントでは、フォールバック認可ポリシーは使用されません。 たとえば、[AllowAnonymous][Authorize(PolicyName="MyPolicy")] を使用する Razor Pages、コントローラー、またはアクション メソッドでは、フォールバック認可ポリシーではなく適用された認可属性が使用されます。

RequireAuthenticatedUser により、現在のインスタンスに DenyAnonymousAuthorizationRequirement が追加されます。これにより、現在のユーザーが認証されます。

UseAuthentication の前に既定の静的ファイル ミドルウェア (app.UseStaticFiles();) が呼び出されるため、wwwroot 下の静的資産にはパブリックにアクセスできます。 MyStaticFiles フォルダー内の静的資産には認証が必要です。 これはサンプル コードで示されています。

認可に基づいてファイルを提供する別の方法:

  • wwwroot や静的ファイル ミドルウェアがアクセスできる任意のディレクトリの外にファイルを配置します。
  • 承認が適用されるアクション メソッドを使用して提供し、FileResult オブジェクトを返します。
[Authorize]
public class BannerImageModel : PageModel
{
    private readonly IWebHostEnvironment _env;

    public BannerImageModel(IWebHostEnvironment env) =>
        _env = env;

    public PhysicalFileResult OnGet()
    {
        var filePath = Path.Combine(
                _env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg");

        return PhysicalFile(filePath, "image/jpeg");
    }
}

ディレクトリ参照

ディレクトリ参照を使用すると、指定したディレクトリ内のディレクトリを一覧表示できます。

ディレクトリ参照は、セキュリティ上の理由から既定で無効になっています。 詳細については、「静的ファイルのセキュリティに関する注意点」を参照してください。

AddDirectoryBrowserUseDirectoryBrowser を使用して、ディレクトリ参照を有効にします。

using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

var fileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.WebRootPath, "images"));
var requestPath = "/MyImages";

// Enable displaying browser links.
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = fileProvider,
    RequestPath = requestPath
});

app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
    FileProvider = fileProvider,
    RequestPath = requestPath
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

上記のコードでは、URL https://<hostname>/MyImages が使用され、各ファイルおよびフォルダーへのリンクを含む wwwroot/images フォルダーのディレクトリが参照できるようになります。

directory browsing

AddDirectoryBrowser により、 HtmlEncoder など、ディレクトリ参照ミドルウェアで必要なサービスが追加されます。 これらのサービスは、AddRazorPages などの他の呼び出しによって追加することもできますが、すべてのアプリでサービスを確実に追加できるように、AddDirectoryBrowser を呼び出すことをお勧めします。

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

既定のページを設定すると、サイトのビジターの開始点になります。 要求 URL にファイルの名前を含めずに wwwroot から既定のファイルを提供するには、UseDefaultFiles メソッドを呼び出します。

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseDefaultFiles();

app.UseStaticFiles();
app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

既定のファイルを提供するには、UseStaticFiles の前に UseDefaultFiles が呼び出される必要があります。 UseDefaultFiles は、ファイルを提供しない URL リライターです。

UseDefaultFiles を使用すると、wwwroot 内のフォルダーの要求では以下のファイルが検索されます。

  • default.htm
  • default.html
  • index.htm
  • index.html

一覧で見つかった最初のファイルは、要求にファイル名が含まれていたかのように提供されます。 ブラウザー URL は、要求された URI を反映し続けます。

次のコードによって、既定のファイル名が mydefault.html に変更されます。

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);

app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

既定のドキュメントの UseFileServer

UseFileServer は、UseStaticFilesUseDefaultFiles、およびオプションとして UseDirectoryBrowser の機能を兼ね備えています。

app.UseFileServer を呼び出すと、静的ファイルと既定ファイルが提供できるようになります。 ディレクトリ参照は有効になりません。

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseFileServer();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

次のコードによって、静的ファイルの提供、既定ファイル、ディレクトリ参照が有効になります。

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseFileServer(enableDirectoryBrowsing: true);

app.UseRouting();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

次のディレクトリ階層があるとします。

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • MyImage.jpg
    • default.html

次のコードによって、MyStaticFiles の静的ファイルの提供、既定ファイル、ディレクトリ参照が有効になります。

using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

app.UseFileServer(new FileServerOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles",
    EnableDirectoryBrowsing = true
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

EnableDirectoryBrowsing プロパティの値が true であるときは、AddDirectoryBrowser を呼び出す必要があります。

前述のファイル階層とコードを使用すると、URL は次のように解決されます。

URI 応答
https://<hostname>/StaticFiles/images/MyImage.jpg MyStaticFiles/images/MyImage.jpg
https://<hostname>/StaticFiles MyStaticFiles/default.html

MyStaticFiles ディレクトリに既定の名前のファイルが存在しない場合、https://<hostname>/StaticFiles によってクリック可能なリンクを含むディレクトリの一覧が返されます。

Static files list

UseDefaultFiles および UseDirectoryBrowser では、末尾の / がないターゲット URI から末尾の / があるターゲット URI へのクライアント側リダイレクトが実行されます。 たとえば、https://<hostname>/StaticFileshttps://<hostname>/StaticFiles/ になります。 StaticFiles ディレクトリ内の相対 URL は、末尾のスラッシュ (/) がないと無効です。

FileExtensionContentTypeProvider

FileExtensionContentTypeProvider クラスには、MIME コンテンツ タイプへのファイル拡張子のマッピングを行う Mappings プロパティが含まれます。 次の例では、いくつかのファイル拡張子が、既知の MIME タイプにマッピングされています。 .rtf 拡張子は置換され、 .mp4 は削除されています。

using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

// 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
{
    ContentTypeProvider = provider
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

MIME content types」 (MIME コンテンツ タイプ) を参照してください。

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

静的ファイル ミドルウェアでは、約 400 の既知のファイル コンテンツ タイプが認識されています。 ユーザーがファイルの種類が不明なファイルを要求した場合、静的ファイル ミドルウェアでその要求がパイプラインの次のミドルウェアに渡されます。 ミドルウェアで要求が処理されない場合、404 見つかりません という応答が返されます。 ディレクトリ参照が有効になっている場合、ディレクトリ一覧にファイルへのリンクが表示されます。

次のコードによって、不明なタイプを提供できるようにし、不明なファイルをイメージとしてレンダリングします。

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles(new StaticFileOptions
{
    ServeUnknownFileTypes = true,
    DefaultContentType = "image/png"
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

上記のコードでは、不明なコンテンツ タイプ ファイルに対する要求は、イメージとして返されます。

警告

ServeUnknownFileTypes を有効にすると、セキュリティ上リスクとなります。 これは既定では無効で、使用は推奨されていません。 非標準の拡張子のファイルを提供する場合、より安全な代替となるのは、FileExtensionContentTypeProvider です。

複数の場所からファイルを提供する

UseStaticFilesUseFileServer の既定では、wwwroot をポイントするファイル プロバイダーが作成されます。 UseStaticFiles および UseFileServer の追加インスタンスを作成して他のファイル プロバイダーを使用すると、他の場所からファイルを提供することができます。 次の例では、UseStaticFiles を 2 回呼び出して、wwwrootstatic の両方からファイルを提供します。

app.UseStaticFiles(); // Serve files from wwwroot
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(builder.Environment.ContentRootPath, "static"))
});

静的ファイルのセキュリティに関する注意点

警告

UseDirectoryBrowserUseStaticFiles では、機密データが漏洩することがあります。 本番では、ディレクトリ参照を無効にすることが、強く推奨されます。 UseStaticFilesUseDirectoryBrowser でどのディレクトリが有効になっているか、慎重にご確認ください。 ディレクトリ全体とそのサブディレクトリが、パブリックにアクセス可能になります。 ファイルは、パブリックに提供するのに適した、<content_root>/wwwroot などの専用ディレクトリに格納します。 これらのファイルは、MVC ビュー、Razor Pages、構成ファイルなどとは別にします。

  • UseDirectoryBrowserUseStaticFiles で公開されるコンテンツの URL では、大文字と小文字が区別され、基になるファイル システムの文字制限の影響を受けます。 たとえば、Windows では大文字と小文字が区別されませんが、macOS と Linux では区別されます。

  • IIS でホストされている ASP.NET Core アプリは、ASP.NET Core モジュールを使用して、静的ファイルの要求を含む、すべての要求をアプリに転送します。 IIS の静的ファイル ハンドラーは使用されず、要求を処理することはできません。

  • IIS マネージャーで次の手順を実行し、サーバーまたは Web サイト レベルで IIS の静的ファイル ハンドラーを削除します。

    1. [モジュール] 機能に移動します。
    2. 一覧の [StaticFileModule] を選択します。
    3. [アクション] サイドバーで、 [削除] をクリックします。

警告

IIS の静的ファイル ハンドラーが有効になっており、かつ、ASP.NET Core モジュールが正しく構成されていない場合、静的ファイルにサービスが提供されます。 これは、たとえば、web.config ファイルが配置されていない場合などで発生します。

  • アプリ プロジェクトの Web ルートの外に、コード ファイル ( .cs.cshtml を含む) を配置します。 これにより、アプリのクライアント側コンテンツとサーバー ベースのコードの間で、論理的な分離が作成されます。 これによって、サーバー側のコードが漏洩するのを防ぎます。

IWebHostEnvironment.WebRootPath を更新して wwwroot の外部のファイルを提供する

IWebHostEnvironment.WebRootPathwwwroot 以外のフォルダーに設定されている場合:

  • 開発環境では、wwwroot と更新された IWebHostEnvironment.WebRootPath の両方で見つかった静的資産が wwwroot から提供されます。
  • 開発以外のどの環境でも、重複する静的資産は、更新された IWebHostEnvironment.WebRootPath フォルダーから提供されます。

空の Web テンプレートを使用して作成された Web アプリについて考えてみましょう。

  • wwwrootwwwroot-customIndex.html ファイルが含まれる。

  • WebRootPath = "wwwroot-custom" を設定する、更新された次の Program.cs ファイルがある。

    var builder = WebApplication.CreateBuilder(new WebApplicationOptions
    {
        Args = args,
        // Look for static files in "wwwroot-custom"
        WebRootPath = "wwwroot-custom"
    });
    
    var app = builder.Build();
    
    app.UseDefaultFiles();
    app.UseStaticFiles();
    
    app.Run();
    

上記のコードで、/ に要求を行うと:

  • 開発環境では wwwroot/Index.html が返される
  • 開発以外のどの環境でも wwwroot-custom/Index.html が返される

確実に wwwroot-custom の資産が返されるようにするには、以下のいずれかの方法を使用します。

  • wwwroot 内の重複する名前付き資産を削除します。

  • Properties/launchSettings.json 内の "ASPNETCORE_ENVIRONMENT""Development" 以外の任意の値に設定します。

  • プロジェクト ファイルで <StaticWebAssetsEnabled>false</StaticWebAssetsEnabled> を設定して、静的 Web 資産を完全に無効にします。 警告: 静的 Web 資産を無効にすると、Razor クラス ライブラリが無効になります。

  • プロジェクト ファイルに次の JSON を追加します。

    <ItemGroup>
        <Content Remove="wwwroot\**" />
    </ItemGroup>
    

次のコードによって、IWebHostEnvironment.WebRootPath は開発以外の値に更新され、重複するコンテンツが wwwroot ではなく wwwroot-custom から返されることが保証されます。

var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
    Args = args,
    // Examine Hosting environment: logging value
    EnvironmentName = Environments.Staging,
    WebRootPath = "wwwroot-custom"
});

var app = builder.Build();

app.Logger.LogInformation("ASPNETCORE_ENVIRONMENT: {env}",
      Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"));

app.Logger.LogInformation("app.Environment.IsDevelopment(): {env}",
      app.Environment.IsDevelopment().ToString());

app.UseDefaultFiles();
app.UseStaticFiles();

app.Run();

その他のリソース

作成者: Rick Anderson および Kirk Larkin

HTML、CSS、画像、JavaScript などの静的ファイルは、既定では ASP.NET Core アプリにより直接クライアントに提供される資産です。

サンプル コードを表示またはダウンロードします (ダウンロード方法)。

静的ファイルの提供

静的ファイルは、プロジェクトの Web ルート ディレクトリ内に格納されています。 既定のディレクトリは {content root}/wwwroot ですが、UseWebRoot メソッドを使用して変更できます。 詳細については、「コンテンツ ルート」および「Web ルート」を参照してください。

CreateDefaultBuilder メソッドでは、コンテンツのルートが現在のディレクトリに設定されます。

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>();
            });
}

上記のコードは、Web アプリ テンプレートを使用して作成されました。

静的ファイルには、Web ルートに対する相対パスを使用してアクセスできます。 たとえば、Web アプリケーション プロジェクト テンプレートでは、wwwroot フォルダー内に次のいくつかのフォルダーが含まれています。

  • wwwroot
    • css
    • js
    • lib

wwwroot/images フォルダーを作成し、wwwroot/images/MyImage.jpg ファイルを追加する場合を考えてみます。 images フォルダー内のファイルにアクセスするための URI 形式は https://<hostname>/images/<image_file_name> です。 たとえば、https://localhost:5001/images/MyImage.jpg

Web ルート内のファイルの提供

既定の Web アプリ テンプレートでは、Startup.Configure 内で UseStaticFiles メソッドが呼び出されます。これにより、静的ファイルを提供できるようになります。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

UseStaticFiles メソッドのパラメーターなしのオーバーロードによって、Web ルート内のファイルが提供可能とマークされます。 次のマークアップは、wwwroot/images/MyImage.jpg を参照します。

<img src="~/images/MyImage.jpg" class="img" alt="My image" />

上記のコードでは、チルダ文字 ~/Web ルートを指します。

Web ルート外のファイルの提供

提供する静的ファイルが Web ルートの外にあるディレクトリ階層について考えます。

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • red-rose.jpg

静的ファイル ミドルウェアを次のように構成すると、要求で red-rose.jpg ファイルにアクセスできます。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    // using Microsoft.Extensions.FileProviders;
    // using System.IO;
    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.ContentRootPath, "MyStaticFiles")),
        RequestPath = "/StaticFiles"
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

前述のコードでは、MyStaticFiles ディレクトリ階層は、StaticFiles URI セグメントでパブリックに公開されています。 https://<hostname>/StaticFiles/images/red-rose.jpg の要求は、red-rose.jpg ファイルを提供します。

次のマークアップは、MyStaticFiles/images/red-rose.jpg を参照します。

<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />

HTTP 応答ヘッダーの設定

StaticFileOptions オブジェクトを使用すると、HTTP 応答ヘッダーを設定できます。 Web ルートから提供される静的ファイルの構成に加えて、次のコードで Cache-Control ヘッダーを設定します。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    const string cacheMaxAge = "604800";
    app.UseStaticFiles(new StaticFileOptions
    {
        OnPrepareResponse = ctx =>
        {
            // using Microsoft.AspNetCore.Http;
            ctx.Context.Response.Headers.Append(
                 "Cache-Control", $"public, max-age={cacheMaxAge}");
        }
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

上記のコードでは、max-age (最長有効期間) を 604800 秒 (7 日) に設定しています。

Response headers showing the Cache-Control header has been added

静的ファイルの承認

ASP.NET Core テンプレートでは、UseAuthorization を呼び出す前に UseStaticFiles が呼び出されます。 ほとんどのアプリがこのパターンに従います。 認可ミドルウェアの前に静的ファイル ミドルウェアが呼び出される場合:

  • 静的ファイルに対して認可チェックは実行されません。
  • 静的ファイル ミドルウェアによって提供される静的ファイル (wwwroot 下にあるものなど) には、パブリックにアクセスできます。

認可に基づいて静的ファイルを提供するには:

  • それらを wwwroot の外部に保存します。
  • UseAuthorization を呼び出した後に、パスを指定して UseStaticFiles を呼び出します。
  • フォールバック認可ポリシーを設定します。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    // wwwroot css, JavaScript, and images don't require authentication.
    app.UseStaticFiles();   

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
                     Path.Combine(env.ContentRootPath, "MyStaticFiles")),
        RequestPath = "/StaticFiles"
    });

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}
public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
            .AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddRazorPages();

        services.AddAuthorization(options =>
        {
            options.FallbackPolicy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .Build();
        });
    }

    // Remaining code ommitted for brevity.

上記のコードでは、フォールバック認可ポリシーによって "すべて" のユーザーを認証することが要求されます。 独自の認可要件を指定する、コントローラー、Razor Pages などのエンドポイントでは、フォールバック認可ポリシーは使用されません。 たとえば、[AllowAnonymous][Authorize(PolicyName="MyPolicy")] を使用する Razor Pages、コントローラー、またはアクション メソッドでは、フォールバック認可ポリシーではなく適用された認可属性が使用されます。

RequireAuthenticatedUser により、現在のインスタンスに DenyAnonymousAuthorizationRequirement が追加されます。これにより、現在のユーザーが認証されます。

UseAuthentication の前に既定の静的ファイル ミドルウェア (app.UseStaticFiles();) が呼び出されるため、wwwroot 下の静的資産にはパブリックにアクセスできます。 MyStaticFiles フォルダー内の静的資産には認証が必要です。 これはサンプル コードで示されています。

認可に基づいてファイルを提供する別の方法:

  • wwwroot や静的ファイル ミドルウェアがアクセスできる任意のディレクトリの外にファイルを配置します。
  • 承認が適用されるアクション メソッドを使用して提供し、FileResult オブジェクトを返します。
[Authorize]
public IActionResult BannerImage()
{
    var filePath = Path.Combine(
        _env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg");

    return PhysicalFile(filePath, "image/jpeg");
}

ディレクトリ参照

ディレクトリ参照を使用すると、指定したディレクトリ内のディレクトリを一覧表示できます。

ディレクトリ参照は、セキュリティ上の理由から既定で無効になっています。 詳細については、「静的ファイルのセキュリティに関する注意点」を参照してください。

ディレクトリ参照を有効にするには、次のメソッドを使用します。

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddDirectoryBrowser();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    // using Microsoft.Extensions.FileProviders;
    // using System.IO;
    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.WebRootPath, "images")),
        RequestPath = "/MyImages"
    });

    app.UseDirectoryBrowser(new DirectoryBrowserOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.WebRootPath, "images")),
        RequestPath = "/MyImages"
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

上記のコードでは、URL https://<hostname>/MyImages が使用され、各ファイルおよびフォルダーへのリンクを含む wwwroot/images フォルダーのディレクトリが参照できるようになります。

directory browsing

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

既定のページを設定すると、サイトのビジターの開始点になります。 要求 URL にファイルの名前を含めずに wwwroot から既定のファイルを提供するには、UseDefaultFiles メソッドを呼び出します。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseDefaultFiles();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

既定のファイルを提供するには、UseStaticFiles の前に UseDefaultFiles が呼び出される必要があります。 UseDefaultFiles は、ファイルを提供しない URL リライターです。

UseDefaultFiles を使用すると、wwwroot 内のフォルダーの要求では以下のファイルが検索されます。

  • default.htm
  • default.html
  • index.htm
  • index.html

一覧で見つかった最初のファイルは、要求にファイル名が含まれていたかのように提供されます。 ブラウザー URL は、要求された URI を反映し続けます。

次のコードによって、既定のファイル名が mydefault.html に変更されます。

var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);
app.UseStaticFiles();

次のコードでは、上記のコードを含めた Startup.Configure を示します。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    var options = new DefaultFilesOptions();
    options.DefaultFileNames.Clear();
    options.DefaultFileNames.Add("mydefault.html");
    app.UseDefaultFiles(options);
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

既定のドキュメントの UseFileServer

UseFileServer は、UseStaticFilesUseDefaultFiles、およびオプションとして UseDirectoryBrowser の機能を兼ね備えています。

app.UseFileServer を呼び出すと、静的ファイルと既定ファイルが提供できるようになります。 ディレクトリ参照は有効にしません。 次のコードでは、UseFileServer を含めた Startup.Configure を示します。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseFileServer();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

次のコードによって、静的ファイルの提供、既定ファイル、ディレクトリ参照が有効になります。

app.UseFileServer(enableDirectoryBrowsing: true);

次のコードでは、上記のコードを含めた Startup.Configure を示します。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseFileServer(enableDirectoryBrowsing: true);

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

次のディレクトリ階層があるとします。

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • MyImage.jpg
    • default.html

次のコードによって、MyStaticFiles の静的ファイルの提供、既定ファイル、ディレクトリ参照が有効になります。

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddDirectoryBrowser();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseStaticFiles(); // For the wwwroot folder.

    // using Microsoft.Extensions.FileProviders;
    // using System.IO;
    app.UseFileServer(new FileServerOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.ContentRootPath, "MyStaticFiles")),
        RequestPath = "/StaticFiles",
        EnableDirectoryBrowsing = true
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

EnableDirectoryBrowsing プロパティの値が true であるときは、AddDirectoryBrowser を呼び出す必要があります。

このファイル階層と前述のコードを使用すると、URL は次のように解決されます。

URI 応答
https://<hostname>/StaticFiles/images/MyImage.jpg MyStaticFiles/images/MyImage.jpg
https://<hostname>/StaticFiles MyStaticFiles/default.html

MyStaticFiles ディレクトリに既定の名前のファイルが存在しない場合、https://<hostname>/StaticFiles によってクリック可能なリンクを含むディレクトリの一覧が返されます。

Static files list

UseDefaultFiles および UseDirectoryBrowser では、末尾の / がないターゲット URI から末尾の / があるターゲット URI へのクライアント側リダイレクトが実行されます。 たとえば、https://<hostname>/StaticFileshttps://<hostname>/StaticFiles/ になります。 StaticFiles ディレクトリ内の相対 URL は、末尾のスラッシュ (/) がないと無効です。

FileExtensionContentTypeProvider

FileExtensionContentTypeProvider クラスには、MIME コンテンツ タイプへのファイル拡張子のマッピングを行う Mappings プロパティが含まれます。 次の例では、いくつかのファイル拡張子が、既知の MIME タイプにマッピングされています。 .rtf 拡張子は置換され、 .mp4 は削除されています。

// using Microsoft.AspNetCore.StaticFiles;
// using Microsoft.Extensions.FileProviders;
// using System.IO;

// 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(env.WebRootPath, "images")),
    RequestPath = "/MyImages",
    ContentTypeProvider = provider
});

app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(env.WebRootPath, "images")),
    RequestPath = "/MyImages"
});

次のコードでは、上記のコードを含めた Startup.Configure を示します。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    // using Microsoft.AspNetCore.StaticFiles;
    // using Microsoft.Extensions.FileProviders;
    // using System.IO;

    // 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(env.WebRootPath, "images")),
        RequestPath = "/MyImages",
        ContentTypeProvider = provider
    });

    app.UseDirectoryBrowser(new DirectoryBrowserOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.WebRootPath, "images")),
        RequestPath = "/MyImages"
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

MIME content types」 (MIME コンテンツ タイプ) を参照してください。

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

静的ファイル ミドルウェアでは、約 400 の既知のファイル コンテンツ タイプが認識されています。 ユーザーがファイルの種類が不明なファイルを要求した場合、静的ファイル ミドルウェアでその要求がパイプラインの次のミドルウェアに渡されます。 ミドルウェアで要求が処理されない場合、404 見つかりません という応答が返されます。 ディレクトリ参照が有効になっている場合、ディレクトリ一覧にファイルへのリンクが表示されます。

次のコードによって、不明なタイプを提供できるようにし、不明なファイルをイメージとしてレンダリングします。

app.UseStaticFiles(new StaticFileOptions
{
    ServeUnknownFileTypes = true,
    DefaultContentType = "image/png"
});

次のコードでは、上記のコードを含めた Startup.Configure を示します。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseStaticFiles(new StaticFileOptions
    {
        ServeUnknownFileTypes = true,
        DefaultContentType = "image/png"
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

上記のコードでは、不明なコンテンツ タイプ ファイルに対する要求は、イメージとして返されます。

警告

ServeUnknownFileTypes を有効にすると、セキュリティ上リスクとなります。 これは既定では無効で、使用は推奨されていません。 非標準の拡張子のファイルを提供する場合、より安全な代替となるのは、FileExtensionContentTypeProvider です。

複数の場所からファイルを提供する

UseStaticFilesUseFileServer の既定では、wwwroot をポイントするファイル プロバイダーが作成されます。 UseStaticFiles および UseFileServer の追加インスタンスを作成して他のファイル プロバイダーを使用すると、他の場所からファイルを提供することができます。 詳細については、次を参照してください。この GitHub の問題します。

静的ファイルのセキュリティに関する注意点

警告

UseDirectoryBrowserUseStaticFiles では、機密データが漏洩することがあります。 本番では、ディレクトリ参照を無効にすることが、強く推奨されます。 UseStaticFilesUseDirectoryBrowser でどのディレクトリが有効になっているか、慎重にご確認ください。 ディレクトリ全体とそのサブディレクトリが、パブリックにアクセス可能になります。 ファイルは、パブリックに提供するのに適した、<content_root>/wwwroot などの専用ディレクトリに格納します。 これらのファイルは、MVC ビュー、Razor Pages、構成ファイルなどとは別にします。

  • UseDirectoryBrowserUseStaticFiles で公開されるコンテンツの URL では、大文字と小文字が区別され、基になるファイル システムの文字制限の影響を受けます。 たとえば、Windows では大文字と小文字が区別されませんが、macOS と Linux では区別されます。

  • IIS でホストされている ASP.NET Core アプリは、ASP.NET Core モジュールを使用して、静的ファイルの要求を含む、すべての要求をアプリに転送します。 IIS の静的ファイル ハンドラーは使用されず、要求を処理することはできません。

  • IIS マネージャーで次の手順を実行し、サーバーまたは Web サイト レベルで IIS の静的ファイル ハンドラーを削除します。

    1. [モジュール] 機能に移動します。
    2. 一覧の [StaticFileModule] を選択します。
    3. [アクション] サイドバーで、 [削除] をクリックします。

警告

IIS の静的ファイル ハンドラーが有効になっており、かつ、ASP.NET Core モジュールが正しく構成されていない場合、静的ファイルにサービスが提供されます。 これは、たとえば、web.config ファイルが配置されていない場合などで発生します。

  • アプリ プロジェクトの Web ルートの外に、コード ファイル ( .cs.cshtml を含む) を配置します。 これにより、アプリのクライアント側コンテンツとサーバー ベースのコードの間で、論理的な分離が作成されます。 これによって、サーバー側のコードが漏洩するのを防ぎます。

その他の技術情報