作成者: Rick Anderson
HTML、CSS、イメージ、JavaScript などの静的ファイルは、ASP.NET Core アプリが既定でクライアントに直接提供するアセットです。
この記事のガイダンスに追加または置き換わる静的ファイルのガイダンス Blazor については、「 ASP.NET Core Blazor 静的ファイル」を参照してください。
静的ファイルを配信する
静的ファイルは、プロジェクトの 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.MapStaticAssets();
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
静的ファイルには、 Web ルートに対する相対パスを使用してアクセスできます。 たとえば、 Web アプリケーション プロジェクト テンプレートには、 wwwroot
フォルダー内のいくつかのフォルダーが含まれています。
wwwroot
css
js
lib
wwwroot/images/MyImage.jpg
ファイルを含むアプリについて考えてみましょう。 images
フォルダー内のファイルにアクセスするための URI 形式はhttps://<hostname>/images/<image_file_name>
。 たとえば、https://localhost:5001/images/MyImage.jpg
のように指定します。
静的資産ルーティング エンドポイント規則のマップ (MapStaticAssets
)
高パフォーマンスの Web アプリを作成するには、ブラウザーへのアセット デリバリーを最適化する必要があります。 MapStaticAssetsで考えられる最適化は次のとおりです。
- ファイルが変更されるか、ブラウザーでキャッシュがクリアされるまで、指定された資産が一度だけ提供されます。 ETag ヘッダーと Last-Modified ヘッダーを設定します。
- アプリの更新後にブラウザーが以前のアセットや古くなったアセットを使用することを防ぐ。 Last-Modified ヘッダーを設定する。
- 適切なキャッシュ ヘッダーを設定する。
- キャッシュ ミドルウェアを使用します。
- 可能な場合は圧縮バージョンのアセットを提供する。 この最適化には縮小は含まれません。
- CDN を使用してユーザーにより近いアセットを提供する。
- 古いバージョンのファイルが再利用されないように資産をフィンガープリントする。
MapStaticAssets
:
- ビルドおよび発行プロセス中に収集された静的 Web 資産に関する情報を、ブラウザーへのファイルの提供を最適化するためにこの情報を処理するランタイム ライブラリと統合します。
- アプリ内の静的資産の配信を最適化するルーティング エンドポイント規則です。 これは、Blazor、Razor Pages、MVC など、すべての UI フレームワークで動作するように設計されています。
MapStaticAssets
対 UseStaticFiles
MapStaticAssets は、.NET 9 以降の ASP.NET Core で使用できます。 UseStaticFiles は、.NET 9 より前のバージョンで使用する必要があります。
UseStaticFiles
は静的ファイルを提供しますが、 MapStaticAssets
と同じレベルの最適化を提供しません。 MapStaticAssets
は、アプリが実行時に知っている資産を提供するために最適化されています。 アプリがディスクや埋め込みリソースなど、他の場所からアセットを提供する場合は、UseStaticFiles
を使用する必要があります。
静的アセットのマップには、 UseStaticFiles
を呼び出すときに使用できない次の利点があります。
- JavaScript (JS) やスタイルシートを含むが、既に圧縮されているイメージアセットとフォントアセットを除く、アプリ内のすべてのアセットのビルド時圧縮。 Gzip (
Content-Encoding: gz
) 圧縮は開発中に使用されます。 発行時に Brotli (Content-Encoding: br
) 圧縮を使用した Gzip が使用されます。 - ビルド時に、各ファイルのコンテンツに基づいたSHA-256ハッシュのBase64エンコードされた文字列を使って、すべての資産のフィンガープリントを行います。 これにより、古いファイルがキャッシュされている場合でも、古いバージョンのファイルを再利用できなくなります。 フィンガープリントされた資産は、
immutable
ディレクティブを使用してキャッシュされるため、ブラウザーは変更されるまで資産を再度要求しません。immutable
ディレクティブをサポートしていないブラウザーの場合は、max-age
ディレクティブが追加されます。- アセットがフィンガープリントされていない場合でも、ファイルのフィンガープリント ハッシュを
ETags
値として使用して、静的アセットごとにコンテンツ ベースのETag
が生成されます。 これにより、コンテンツが変更された場合 (またはファイルが初めてダウンロードされる) 場合にのみ、ブラウザーでファイルがダウンロードされるようになります。 - 内部的には、フレームワークは物理資産を指紋にマップします。これにより、アプリは次のことができます。
- アセットがフィンガープリントされていない場合でも、ファイルのフィンガープリント ハッシュを
- Visual Studio ホット リロード開発テスト中:
- アプリの実行中にファイルが変更されたときに問題が発生しないように、資産から整合性情報が削除されます。
- ブラウザーが常に現在のコンテンツを確実に取得できるように、静的資産はキャッシュされません。
静的アセットのマップでは、縮小やその他のファイル変換の機能は提供されません。 縮小は通常、カスタム コードまたは サード パーティ製ツールによって処理されます。
次の機能は、 UseStaticFiles
ではサポートされていますが、 MapStaticAssets
ではサポートされていません。
- ディスクまたは埋め込みリソース、またはその他の場所からファイルを提供する
- Web ルート外のファイルの提供
- HTTP 応答ヘッダーを設定する
- ディレクトリの参照
- 既定のドキュメントを提供する
FileExtensionContentTypeProvider
- 複数の場所からファイルを提供する
- ディスクまたは埋め込みリソース、またはその他の場所からファイルを提供する
- Web ルート外のファイルの提供
- HTTP 応答ヘッダーを設定する
- ディレクトリの参照
- 既定のドキュメントを提供する
FileExtensionContentTypeProvider
- 複数の場所からファイルを提供する
Web ルートでファイルを提供する
既定の Web アプリ テンプレートでは、MapStaticAssetsの Program.cs
メソッドが呼び出され、静的ファイルを提供できます。
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.MapStaticAssets();
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
パラメーターなしの MapStaticAssets
メソッドオーバーロードは、 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(); //Serve files from wwwroot
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles"
});
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
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().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
上記のコードでは、静的ファイルをローカル キャッシュで 1 週間公開しています。
静的ファイルの承認
ASP.NET Core テンプレートは、MapStaticAssetsを呼び出す前にUseAuthorizationを呼び出します。 ほとんどのアプリは、このパターンに従います。 承認ミドルウェアの前に MapStaticAssets
が呼び出されたとき:
- 静的ファイルに対して承認チェックは実行されません。
- 静的ファイル ミドルウェアによって提供される静的ファイル (
wwwroot
下の静的ファイルなど) には、パブリックにアクセスできます。
承認に基づいて静的ファイルを処理するには、 静的ファイルの承認に関するページを参照してください。
複数の場所からファイルを提供する
Razor ファイルを表示する次の/MyStaticFiles/image3.png
ページについて考えてみましょう。
@page
<p> Test /MyStaticFiles/image3.png</p>
<img src="~/image3.png" class="img" asp-append-version="true" alt="Test">
UseStaticFiles
とUseFileServer
はwwwroot
を指すファイルプロバイダーにデフォルト設定されています。 UseStaticFiles
とUseFileServer
の追加インスタンスは、他の場所のファイルを提供するために、他のファイル プロバイダーと共に提供できます。 次の例では、 UseStaticFiles
を 2 回呼び出して、 wwwroot
と MyStaticFiles
の両方のファイルを処理します。
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"))
});
上記のコードの使用:
/MyStaticFiles/image3.png
ファイルが表示されます。- タグ ヘルパーはAppendVersionに依存するためWebRootFileProviderイメージ タグ ヘルパーは適用されません。
WebRootFileProvider
は、MyStaticFiles
フォルダーを含むように更新されていません。
次のコードは、 WebRootFileProvider
を更新します。これにより、イメージ タグ ヘルパーがバージョンを提供できるようになります。
var webRootProvider = new PhysicalFileProvider(builder.Environment.WebRootPath);
var newPathProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"));
var compositeProvider = new CompositeFileProvider(webRootProvider,
newPathProvider);
// Update the default provider.
app.Environment.WebRootFileProvider = compositeProvider;
app.MapStaticAssets();
注
上記の方法は、 Razor Pages および MVC アプリに適用されます。 Blazor Web Appに適用されるガイダンスについては、ASP.NET Core Blazor静的ファイルに関するページを参照してください。
IWebHostEnvironment.WebRootPath を更新して wwwroot の外部でファイルを提供する
IWebHostEnvironment.WebRootPathがwwwroot
以外のフォルダーに設定されている場合:
- 開発環境では、
wwwroot
と更新されたIWebHostEnvironment.WebRootPath
の両方で見つかった静的資産がwwwroot
から提供されます。 - 開発以外の環境では、更新された
IWebHostEnvironment.WebRootPath
フォルダーから重複する静的資産が提供されます。
空の Web テンプレートを使用して作成された Web アプリについて考えてみましょう。
Index.html
およびwwwroot
にwwwroot-custom
ファイルを含む。Program.cs
を設定する次の更新されたWebRootPath = "wwwroot-custom"
ファイルを使用します。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.MapStaticAssets(); app.Run();
上記のコードで、/
に要求を行うと:
- 開発環境で
wwwroot/Index.html
を返す - 開発以外のどの環境でも
wwwroot-custom/Index.html
が返される
wwwroot-custom
から資産が確実に返されるようにするには、次のいずれかの方法を使用します。
wwwroot
で重複する名前付き資産を削除します。"ASPNETCORE_ENVIRONMENT"
のProperties/launchSettings.json
を"Development"
以外の値に設定します。プロジェクト ファイルで
<StaticWebAssetsEnabled>false</StaticWebAssetsEnabled>
を設定して、静的 Web アセットを完全に無効にします。 警告:静的 Web アセットを無効にすると、クラス ライブラリRazor無効になります。次の XML をプロジェクト ファイルに追加します。
<ItemGroup> <Content Remove="wwwroot\**" /> </ItemGroup>
次のコードは、IWebHostEnvironment.WebRootPath
開発以外の値に更新され、wwwroot-custom
ではなくwwwroot
から重複するコンテンツが返されます。
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.MapStaticAssets();
app.Run();
その他のリソース
ASP.NET Core