ASP.NET Core Blazor の静的ファイル

注意

これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

警告

このバージョンの ASP.NET Core はサポート対象から除外されました。 詳細については、「.NET および .NET Core サポート ポリシー」を参照してください。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

重要

この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。

現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

この記事では、Blazor アプリで静的ファイルを提供する構成について説明します。

静的資産のミドルウェア

このセクションは、サーバー側の Blazor アプリに適用されます。

静的資産の提供は、次の表で説明する 2 つのミドルウェアのいずれかで管理されます。

ミドルウェア API .NET のバージョン 説明
Map Static Assets MapStaticAssets .NET 9 以降 クライアントへの静的資産の配信を最適化します。
静的ファイル UseStaticFiles すべての .NET バージョン MapStaticAssets の最適化なしでクライアントに静的資産を提供しますが、MapStaticAssets で管理できない一部のタスクに役立ちます。

アプリの要求処理パイプラインで MapStaticAssets を呼び出すことで Map Static Assets ミドルウェアを構成し、次の操作を実行します。

MapStaticAssets は、ビルドおよび発行プロセスを組み合わせて動作することで、アプリ内の静的資産に関する情報を収集します。 この情報は、静的資産をブラウザーに効率的に提供するために、ランタイム ライブラリによって使用されます。

MapStaticAssets は、ほとんどの状況で UseStaticFiles に代わることができます。 ただし、MapStaticAssets は、ビルドおよび発行時にアプリ内の既知の場所から資産を提供するために最適化されています。 アプリがディスクや埋め込みリソースなど、他の場所からアセットを提供する場合は、UseStaticFiles を使用する必要があります。

MapStaticAssets には、UseStaticFiles を呼び出す場合には得られない以下の利点があります。

  • JavaScript (JS) とスタイルシートを含むアプリ内のすべての資産に対するビルド時の圧縮。ただし、既に圧縮されている画像とフォントの資産は除外されます。 開発時には Gzip (Content-Encoding: gz) 圧縮が使用されます。 発行時には Brotli (Content-Encoding: br) 圧縮による Gzip が使用されます。
  • 各ファイルのコンテンツの SHA-256 ハッシュを Base64 でエンコードした文字列を使用して、ビルド時にすべての資産に対してフィンガープリントします。 こうすることで、古いファイルがキャッシュされている場合でも、旧バージョンのファイルを再利用できなくなります。 フィンガープリントされた資産は、immutable ディレクティブを使用してキャッシュされます。その結果、その資産が変更されるまで、ブラウザーはそれに対して再度要求しなくなります。 immutable ディレクティブをサポートしていないブラウザーの場合は、max-age ディレクティブが追加されます。
    • 資産がフィンガープリントされていない場合でも、ファイルのフィンガープリント ハッシュが ETag 値として使用され、静的資産ごとにコンテンツベースの ETags が生成されます。 これにより、コンテンツが変更された場合 (またはファイルが初めてダウンロードされる場合) にのみ、ブラウザーはファイルをダウンロードするようになります。
    • 内部的には、Blazor により、物理資産はそのフィンガープリントにマップされるので、アプリは以下のことが可能になります。
      • Razor コンポーネント スコープの CSS for Blazor の CSS 分離機能JS インポート マップで記述された JS など、自動生成された Blazor 資産を検索します。
      • ページの <head> コンテンツにリンク タグを生成して、資産をプリロードします。
  • Visual Studio ホット リロード開発テスト中:
    • アプリの実行中にファイルが変更された場合の問題を回避するために、整合性情報は資産から削除されます。
    • ブラウザーが常に最新のコンテンツを取得できるように、静的資産はキャッシュされません。

対話型 WebAssembly または対話型自動レンダリング モードが有効な場合:

  • Blazor により、リソース コレクションを JS モジュールとして公開するエンドポイントが作成されます。
  • WebAssembly コンポーネントがページにレンダリングされると、URL は永続化されたコンポーネント状態として要求の本文に出力されます。
  • WebAssembly の起動時に、Blazor により、URL を取得し、モジュールをインポートし、資産コレクションを取得する関数を呼び出し、メモリ内に再構築する処理が行われます。 URL はコンテンツに固有であり、無期限にキャッシュされるため、このオーバーヘッド コストがかかるのは、アプリが更新されるまでユーザーごとに 1 回のみです。
  • リソース コレクションは人間が判読できる URL (_framework/resource-collection.js) でも公開されているため、JS からリソース コレクションにアクセスして強化されたナビゲーションを利用したり、他のフレームワークとサードパーティ コンポーネントの機能を実装したりすることができます。

Map Static Assets Middleware に、縮小やその他のファイル変換の機能はありません。 通常、縮小はカスタム コードまたはサードパーティ ツールによって処理されます。

静的ファイル ミドルウェア (UseStaticFiles) は、MapStaticAssets が処理できない次の状況で役に立ちます。

Map Static File Middleware で資産を使用する

このセクションは、サーバー側の Blazor アプリに適用されます。

資産は、特定の資産のフィンガープリントされた URL を解決する ComponentBase.Assets プロパティを介して使用されます。 次の例で、ブートストラップ、Blazor プロジェクト テンプレート アプリ スタイルシート (app.css)、CSS 分離スタイルシートは、ルート コンポーネント (通常は App コンポーネント (Components/App.razor)) でリンクされています。

<link rel="stylesheet" href="@Assets["bootstrap/bootstrap.min.css"]" />
<link rel="stylesheet" href="@Assets["app.css"]" />
<link rel="stylesheet" href="@Assets["BlazorWeb-CSharp.styles.css"]" />

マップをインポートする

このセクションは、サーバー側の Blazor アプリに適用されます。

ImportMap コンポーネントは、モジュール スクリプトのインポート マップを定義するインポート マップ要素 (<script type="importmap"></script>) を表します。 ImportMap コンポーネントは、ルート コンポーネントの <head> コンテンツ、通常は App コンポーネント (Components/App.razor) に配置されます。

<ImportMap />

カスタムの ImportMapDefinitionImportMap コンポーネントに割り当てられていない場合、インポート マップはアプリの資産に基づいて生成されます。

次の例は、カスタム インポート マップ定義とそれによって作成されるインポート マップを示しています。

基本的なインポート マップ:

new ImportMapDefinition(
    new Dictionary<string, string>
    {
        { "jquery", "https://cdn.example.com/jquery.js" },
    },
    null,
    null);

上のコードにより、次のインポート マップが生成されます。

{
  "imports": {
    "jquery": "https://cdn.example.com/jquery.js"
  }
}

スコープ指定ありのインポート マップ:

new ImportMapDefinition(
    null,
    new Dictionary<string, IReadOnlyDictionary<string, string>>
    {
        ["/scoped/"] = new Dictionary<string, string>
        {
            { "jquery", "https://cdn.example.com/jquery.js" },
        }
    },
    null);

上のコードにより、次のインポート マップが生成されます。

{
  "scopes": {
    "/scoped/": {
      "jquery": "https://cdn.example.com/jquery.js"
    }
  }
}

整合性を備えたインポート マップ:

new ImportMapDefinition(
    new Dictionary<string, string>
    {
        { "jquery", "https://cdn.example.com/jquery.js" },
    },
    null,
    new Dictionary<string, string>
    {
        { "https://cdn.example.com/jquery.js", "sha384-abc123" },
    });

上のコードにより、次のインポート マップが生成されます。

{
  "imports": {
    "jquery": "https://cdn.example.com/jquery.js"
  },
  "integrity": {
    "https://cdn.example.com/jquery.js": "sha384-abc123"
  }
}

インポート マップ定義 (ImportMapDefinition) を ImportMapDefinition.Combine と組み合わせます。

静的資産を対応する一意の URL にマップする、ResourceAssetCollection から作成されたインポート マップ:

ImportMapDefinition.FromResourceCollection(
    new ResourceAssetCollection(
    [
        new ResourceAsset(
            "jquery.fingerprint.js",
            [
                new ResourceAssetProperty("integrity", "sha384-abc123"),
                new ResourceAssetProperty("label", "jquery.js"),
            ])
    ]));

上のコードにより、次のインポート マップが生成されます。

{
  "imports": {
    "./jquery.js": "./jquery.fingerprint.js"
  },
  "integrity": {
    "jquery.fingerprint.js": "sha384-abc123"
  }
}

静的ファイル ミドルウェアを構成し、アプリの要求処理パイプラインで UseStaticFiles を呼び出して、静的資産をクライアントに提供します。 詳細については、「ASP.NET Core の静的ファイル」をご覧ください。

.NET 8 より前のリリースでは、 Blazor スクリプトなどの Blazor フレームワークの静的ファイルは、静的ファイル ミドルウェアを介して提供されます。 .NET 8 以降では、 Blazor フレームワークの静的ファイルはエンドポイント ルーティングを使用してマップされ、静的ファイル ミドルウェアは使用されなくなりました。

このセクションは、すべての .NET リリースと Blazor アプリに適用されます。

次の表は、静的ファイルの <link> href の形式を .NET リリースごとにまとめたものです。

静的ファイル リンクが配置される <head> コンテンツの場所については、「ASP.NET Core Blazor プロジェクトの構造」を参照してください。 静的資産リンクは、個々の Razor コンポーネントの <HeadContent> コンポーネントを使用して指定することもできます。

静的ファイル リンクが配置される <head> コンテンツの場所については、「ASP.NET Core Blazor プロジェクトの構造」を参照してください。

.NET 9 以降

アプリの種類 href
Blazor Web アプリ @Assets["{PATH}"] <link rel="stylesheet" href="@Assets["app.css"]" />
<link href="@Assets["_content/ComponentLib/styles.css"]" rel="stylesheet" />
Blazor Server† @Assets["{PATH}"] <link href="@Assets["css/site.css"]" rel="stylesheet" />
<link href="@Assets["_content/ComponentLib/styles.css"]" rel="stylesheet" />
スタンドアロン Blazor WebAssembly {PATH} <link rel="stylesheet" href="css/app.css" />
<link href="_content/ComponentLib/styles.css" rel="stylesheet" />

.NET 8.x

アプリの種類 href
Blazor Web アプリ {PATH} <link rel="stylesheet" href="app.css" />
<link href="_content/ComponentLib/styles.css" rel="stylesheet" />
Blazor Server† {PATH} <link href="css/site.css" rel="stylesheet" />
<link href="_content/ComponentLib/styles.css" rel="stylesheet" />
スタンドアロン Blazor WebAssembly {PATH} <link rel="stylesheet" href="css/app.css" />
<link href="_content/ComponentLib/styles.css" rel="stylesheet" />

.NET 7.x 以前

アプリの種類 href
Blazor Server† {PATH} <link href="css/site.css" rel="stylesheet" />
<link href="_content/ComponentLib/styles.css" rel="stylesheet" />
ホステッド Blazor WebAssembly‡ {PATH} <link href="css/app.css" rel="stylesheet" />
<link href="_content/ComponentLib/styles.css" rel="stylesheet" />
Blazor WebAssembly {PATH} <link href="css/app.css" rel="stylesheet" />
<link href="_content/ComponentLib/styles.css" rel="stylesheet" />

† Blazor Server は .NET 8 以降でサポートされていますが、.NET 7 より後のバージョンではプロジェクト テンプレートではなくなりました。
‡ .NET 8 以降を採用する場合は、ホステッド Blazor WebAssembly アプリを Blazor Web アプリに更新することをお勧めします。

静的 Web アセット プロジェクト モード

このセクションは、Blazor Web アプリの .Client プロジェクトに適用されます。

Blazor Web アプリの .Client プロジェクトで必要な <StaticWebAssetProjectMode>Default</StaticWebAssetProjectMode> 設定は、Blazor WebAssembly 静的アセットの動作を既定値に戻して、プロジェクトがホストされているプロジェクトの一部として動作するようにします。 Blazor WebAssembly SDK (Microsoft.NET.Sdk.BlazorWebAssembly) は、ライブラリからの出力を単に消費するサーバーと "スタンドアロン" モードで連携するように、特定の方法で静的 Web アセットを構成します。 これは Blazor Web アプリには適していません。ここでは、アプリの WebAssembly 部分がホストの論理部分であり、もっとライブラリのように動作する必要があります。 たとえば、プロジェクトは styles バンドル (たとえば、BlazorSample.Client.styles.css) を公開せず、代わりにホストに project バンドルのみを提供するため、ホストは独自の styles バンドルに組み込むことができます。

<StaticWebAssetProjectMode>の値 (Default) の変更や、 .Client プロジェクトからのプロパティの削除はサポートされていません

Development 環境の静的ファイル

このセクションは、サーバー側の静的ファイルに適用されます。

アプリがローカルで実行されている場合、静的 Web アセットは、Development 環境内でのみ既定で有効になります。 ローカル開発およびテスト中 (たとえば、Staging) の Development 以外の環境で静的ファイルを有効にするには Program ファイルの WebApplicationBuilder 上の UseStaticWebAssets を呼び出します。

警告

運用環境で呼び出された場合は、ディスク上の "プロジェクト以外の別の場所" からファイルを処理するため、運用環境で機能をアクティブ化しないように、"正確な環境"UseStaticWebAssets を呼び出します。 このセクションの例では、IsStaging を呼び出して Staging 環境を確認します。

if (builder.Environment.IsStaging())
{
    builder.WebHost.UseStaticWebAssets();
}

Blazor WebAssembly 資産のプレフィックス

"このセクションは Blazor WebAssembly に適用されます。"

WebAssemblyComponentsEndpointOptions.PathPrefix エンドポイント オプションを使用して、資産のプレフィックスを示すパス文字列 Blazor WebAssembly を設定します。 パスは、参照先 Blazor WebAssembly アプリケーション プロジェクトに対応している必要があります。

endpoints.MapRazorComponents<App>()
    .AddInteractiveWebAssemblyRenderMode(options => 
        options.PathPrefix = "{PATH PREFIX}");

前の例では、{PATH PREFIX} プレースホルダーはパス プレフィックスで、スラッシュ (/) で始まる必要があります。

次の例では、パス プレフィックス が /path-prefix に設定されています。

endpoints.MapRazorComponents<App>()
    .AddInteractiveWebAssemblyRenderMode(options => 
        options.PathPrefix = "/path-prefix");

静的な Web 資産のベース パス

このセクションは、スタンドアロンの Blazor WebAssembly アプリに適用されます。

既定では、アプリを発行すると、発行された出力のルート パス (/) に、Blazor フレームワーク ファイル (_framework フォルダー資産) を含むアプリの静的アセットが格納されます。 プロジェクト ファイル (.csproj) で指定された <StaticWebAssetBasePath> によって、ベース パスが非ルート パスに設定されます。

<PropertyGroup>
  <StaticWebAssetBasePath>{PATH}</StaticWebAssetBasePath>
</PropertyGroup>

前の例では、{PATH} プレースホルダーがパスです。

<StaticWebAssetBasePath> プロパティを設定しない場合、スタンドアロンのアプリは /BlazorStandaloneSample/bin/Release/{TFM}/publish/wwwroot/ で発行されます。

前の例では、{TFM} プレースホルダーはターゲット フレームワーク モニカー (TFM) (net6.0 など) です。

スタンドアロンの Blazor WebAssembly アプリの <StaticWebAssetBasePath> プロパティで、発行された静的資産パスが app1 に設定されている場合、発行された出力のアプリへのルート パスは /app1 です。

スタンドアロンの Blazor WebAssembly アプリのプロジェクト ファイル (.csproj) で、次のようにします。

<PropertyGroup>
  <StaticWebAssetBasePath>app1</StaticWebAssetBasePath>
</PropertyGroup>

発行された出力では、スタンドアロンの Blazor WebAssembly アプリへのパスは /BlazorStandaloneSample/bin/Release/{TFM}/publish/wwwroot/app1/ です。

前の例では、{TFM} プレースホルダーはターゲット フレームワーク モニカー (TFM) (net6.0 など) です。

このセクションは、スタンドアロンの Blazor WebAssembly アプリとホストされている Blazor WebAssembly ソリューションに適用されます。

既定では、アプリを発行すると、発行された出力のルート パス (/) に、Blazor フレームワーク ファイル (_framework フォルダー資産) を含むアプリの静的アセットが格納されます。 プロジェクト ファイル (.csproj) で指定された <StaticWebAssetBasePath> によって、ベース パスが非ルート パスに設定されます。

<PropertyGroup>
  <StaticWebAssetBasePath>{PATH}</StaticWebAssetBasePath>
</PropertyGroup>

前の例では、{PATH} プレースホルダーがパスです。

<StaticWebAssetBasePath> プロパティを設定しない場合、ホストされているソリューションのクライアント アプリまたはスタンドアロン アプリは、次のパスで発行されます。

  • ホストされている Blazor WebAssembly ソリューションの Server プロジェクトの場合: /BlazorHostedSample/Server/bin/Release/{TFM}/publish/wwwroot/
  • スタンドアロン Blazor WebAssembly アプリの場合: /BlazorStandaloneSample/bin/Release/{TFM}/publish/wwwroot/

ホストされている Blazor WebAssembly アプリの Client プロジェクトまたはスタンドアロンの Blazor WebAssembly アプリの <StaticWebAssetBasePath> プロパティで、発行された静的資産パスが app1 に設定されている場合、発行された出力のアプリへのルート パスは /app1 です。

Client アプリのプロジェクト ファイル (.csproj) またはスタンドアロンの Blazor WebAssembly アプリのプロジェクト ファイル (.csproj) の場合:

<PropertyGroup>
  <StaticWebAssetBasePath>app1</StaticWebAssetBasePath>
</PropertyGroup>

発行された出力で:

  • ホストされている Blazor WebAssembly ソリューションの Server プロジェクトでのクライアント アプリへのパス: /BlazorHostedSample/Server/bin/Release/{TFM}/publish/wwwroot/app1/
  • スタンドアロン Blazor WebAssembly アプリへのパス: /BlazorStandaloneSample/bin/Release/{TFM}/publish/wwwroot/app1/

<StaticWebAssetBasePath> プロパティは、1 つのホストされた展開で複数の Blazor WebAssembly アプリの発行済み静的資産へのパスを制御するために最も一般的に使用されます。 詳細については、「複数のホストされた ASP.NET Core Blazor WebAssembly アプリ」を参照してください。 プロパティは、スタンドアロンの Blazor WebAssembly アプリでも有効です。

前の例では、{TFM} プレースホルダーはターゲット フレームワーク モニカー (TFM) (net6.0 など) です。

ファイル マッピングと静的ファイルのオプション

このセクションは、サーバー側の静的ファイルに適用されます。

FileExtensionContentTypeProvider を使用して追加のファイル マッピングを作成するか、他の StaticFileOptions を構成するには、次の方法のうち 1 つを使用します。 次の例では、{EXTENSION} プレースホルダーはファイル拡張子、{CONTENT TYPE} プレースホルダーはコンテンツ タイプです。 次の API の名前空間は Microsoft.AspNetCore.StaticFiles です。

  • StaticFileOptions を使用して Program依存関係の挿入 (DI) を使ってオプションを構成します:

    var provider = new FileExtensionContentTypeProvider();
    provider.Mappings["{EXTENSION}"] = "{CONTENT TYPE}";
    
    builder.Services.Configure<StaticFileOptions>(options =>
    {
        options.ContentTypeProvider = provider;
    });
    
    app.UseStaticFiles();
    
  • StaticFileOptionsProgram ファイル内の UseStaticFiles に直接渡します。

    var provider = new FileExtensionContentTypeProvider();
    provider.Mappings["{EXTENSION}"] = "{CONTENT TYPE}";
    
    app.UseStaticFiles(new StaticFileOptions { ContentTypeProvider = provider });
    

FileExtensionContentTypeProvider を使用して追加のファイル マッピングを作成するか、他の StaticFileOptions を構成するには、次の方法のうち 1 つを使用します。 次の例では、{EXTENSION} プレースホルダーはファイル拡張子、{CONTENT TYPE} プレースホルダーはコンテンツ タイプです。

  • StaticFileOptions を使用して Program依存関係の挿入 (DI) を使ってオプションを構成します:

    using Microsoft.AspNetCore.StaticFiles;
    
    ...
    
    var provider = new FileExtensionContentTypeProvider();
    provider.Mappings["{EXTENSION}"] = "{CONTENT TYPE}";
    
    builder.Services.Configure<StaticFileOptions>(options =>
    {
        options.ContentTypeProvider = provider;
    });
    

    この方法では、Blazor スクリプトの処理に使用されるのと同じファイル プロバイダーが構成されます。 カスタム構成が Blazor スクリプトの提供を妨げないことを確認します。 たとえば、provider.Mappings.Remove(".js") でプロバイダーを構成することによって、JavaScript ファイルのマッピングを削除しないでください。

  • Program ファイル内で次の 2 つの UseStaticFiles の呼び出しを使用します:

    • StaticFileOptions を使用した最初の呼び出しでカスタム ファイル プロバイダーを構成します。
    • 2 番目のミドルウェアは、Blazor フレームワークが提供するデフォルトの静的ファイル構成を使用する Blazor スクリプトを提供します。
    using Microsoft.AspNetCore.StaticFiles;
    
    ...
    
    var provider = new FileExtensionContentTypeProvider();
    provider.Mappings["{EXTENSION}"] = "{CONTENT TYPE}";
    
    app.UseStaticFiles(new StaticFileOptions { ContentTypeProvider = provider });
    app.UseStaticFiles();
    
  • MapWhen を使用してカスタムの静的ファイル ミドルウェアを実行することで、_framework/blazor.server.js の提供の妨げにならないようにすることができます。

    app.MapWhen(ctx => !ctx.Request.Path
        .StartsWithSegments("/_framework/blazor.server.js"),
            subApp => subApp.UseStaticFiles(new StaticFileOptions() { ... }));
    

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

このセクションのガイダンスが適用されるのは Blazor Web アプリに対してだけです。

CompositeFileProvider を使用して複数の場所からファイルを提供するには:

例:

サーバー プロジェクト内に AdditionalStaticAssets という名前の新しいフォルダーを作成します。 画像をフォルダーに配置します。

サーバー プロジェクトの Program ファイルの先頭に、次の using ステートメントを追加します。

using Microsoft.Extensions.FileProviders;

サーバー プロジェクトの Program ファイルで、UseStaticFiles の呼び出しの "前に" 次のコードを追加します。

var secondaryProvider = new PhysicalFileProvider(
    Path.Combine(builder.Environment.ContentRootPath, "AdditionalStaticAssets"));
app.Environment.WebRootFileProvider = new CompositeFileProvider(
    app.Environment.WebRootFileProvider, secondaryProvider);

アプリの Home コンポーネント (Home.razor) マークアップで、以下のように <img> タグを使用して画像を参照します。

<img src="{IMAGE FILE NAME}" alt="{ALT TEXT}" />

前の例の場合:

  • {IMAGE FILE NAME} プレースホルダーは画像のファイル名です。 画像ファイルが AdditionalStaticAssets フォルダーのルートにある場合は、パス セグメントを指定する必要はありません。
  • {ALT TEXT} プレースホルダーは、画像の代替テキストです。

アプリを実行します。

その他のリソース