ASP.NET Core の Razor クラス ライブラリ プロジェクトを使用した再利用可能 UI の作成

作成者: Rick Anderson

Razor ビュー、ページ、コントローラー、ページ モデル、Razor コンポーネントビュー コンポーネント、データ モデルは、Razor クラス ライブラリ (RCL) に組み込むことが可能です。 RCL はパッケージ化し、再利用できます。 アプリケーションには RCL を含めることができます。また、それに含まれるビューやページをオーバーライドできます。 Web アプリと RCL の両方にビュー、部分ビュー、Razor ページがあるとき、Web アプリの Razor マークアップ ( .cshtml ファイル) が優先されます。

npm と webpack を Razor クラス ライブラリのビルド プロセスに統合する方法については、「Razor クラス ライブラリのクライアント Web アセットをビルドする」を参照してください。

Razor UI を含むクラス ライブラリの作成

  • Visual Studio から [新しいプロジェクトの作成] を選択します。
  • [Razor クラス ライブラリ]>[次へ] の順に選択します。
  • ライブラリに名前を付け (例: "RazorClassLib")、[作成] を選択します。 生成されたビュー ライブラリとファイル名の競合を避けるため、ライブラリ名の末尾が .Views ではないことを確認します。
  • ライブラリにページやビューを含める必要がある場合は、[サポート ページとビュー] を選択します。 既定では、Razor コンポーネントのみがサポートされています。 [作成] を選択します。

Razor クラス ライブラリ (RCL) テンプレートは Razor コンポーネント開発での既定です。 [ページとビューのサポート] オプションによって、ページとビューがサポートされます。 Blazor での RCL サポートについて詳しくは、「ASP.NET Core Razor コンポーネントを Razor クラス ライブラリ (RCL) から使用する」をご覧ください。

RCL に Razor ファイルを追加します。

ASP.NET Core テンプレートでは、RCL コンテンツが Areas フォルダーにあると見なされます。 ~/Areas/Pages ではなく ~/Pages でコンテンツを公開する RCL を作成する場合は、後述の「RCL ページのレイアウト」を参照してください。

RCL コンテンツを参照する

RCL は次によって参照できます。

ビュー、部分ビュー、ページのオーバーライド

Web アプリと RCL の両方にビュー、部分ビュー、Razor ページがある場合は、Web アプリの Razor マークアップ (.cshtml ファイル) が優先されます。 たとえば、WebApp1/Areas/MyFeature/Pages/Page1.cshtml を WebApp1 に追加すると、WebApp1 の Page1 は RCL の Page1 よりも優先されます。

サンプルのダウンロードで、WebApp1/Areas/MyFeature2 の名前を WebApp1/Areas/MyFeature に変更して、優先順位をテストします。

RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml 部分ビューを WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml にコピーします。 新しい場所を示すようにマークアップを更新します。 アプリをビルドして実行し、アプリの部分ビューが使用されていることを確認します。

RCL で Razor Pages を使用する場合は、ホスティング アプリで Razor Pages サービスとエンドポイントを有効にします。

var builder = WebApplication.CreateBuilder(args);

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

var app = builder.Build();

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

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

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.MapRazorPages();
app.Run();

RCL ページのレイアウト

RCL コンテンツを Web アプリの Pages フォルダーの一部であるかのように参照するには、次のファイル構造で RCL プロジェクトを作成します。

  • RazorUIClassLib/Pages
  • RazorUIClassLib/Pages/Shared

RazorUIClassLib/Pages/Shared に 2 つの部分ファイル (_Header.cshtml_Footer.cshtml) が含まれているとします。 これらの <partial> タグを _Layout.cshtml ファイルに追加できます。

<body>
  <partial name="_Header">
  @RenderBody()
  <partial name="_Footer">
</body>

_ViewStart.cshtml ファイルを、RCL プロジェクトの Pages フォルダーに追加して、ホスト Web アプリの _Layout.cshtml ファイルを使用します。

@{
    Layout = "_Layout";
}

静的アセットを含む RCL を作成する

RCL では、RCL または RCL の使用アプリで参照できる静的なコンパニオン アセットが必要になる場合があります。 ASP.NET Core では、使用アプリで利用できる静的アセットを含む RCL の作成が可能です。

コンパニオン アセットを RCL の一部として含めるには、クラス ライブラリに wwwroot フォルダーを作成し、必要なファイルをすべてそのフォルダーに含めます。

RCL をパックすると、wwwroot フォルダー内のすべてのコンパニオン アセットがパッケージに自動的に含まれます。

Nuget.exe バージョン nuget pack ではなく、dotnet pack コマンドを使用します。

クライアント Web 資産をビルド プロセスに追加する

クライアント Web 資産をビルド パイプラインに統合することは簡単ではありません。 詳細については、「Build client web assets for your Razor Class Library (Razor クラス ライブラリのクライアント Web 資産を構築する)」を参照してください。

静的アセットを除外する

静的アセットを除外するには、目的の除外パスをプロジェクトファイル内の $(DefaultItemExcludes) プロパティ グループに追加します。 各エントリは、セミコロン (;) で区切ります。

次の例では、wwwroot フォルダー内の lib.css スタイルシートが静的アセットとは見なされず、公開された RCL には含まれていません。

<PropertyGroup>
  <DefaultItemExcludes>$(DefaultItemExcludes);wwwroot\lib.css</DefaultItemExcludes>
</PropertyGroup>

Typescript の統合

TypeScript ファイルを RCL に含めるには、次の操作を行います。

  1. プロジェクトで Microsoft.TypeScript.MSBuild NuGet パッケージを参照します。

    Note

    .NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の "パッケージのインストールと管理" に関する記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。

  2. TypeScript ファイル (.ts) を wwwroot フォルダーの外側に配置します。 たとえば、ファイルを Client フォルダーに配置します。

  3. wwwroot フォルダーの TypeScript ビルド出力を構成します。 プロジェクト ファイルの PropertyGroup の内側に TypescriptOutDir プロパティを設定します。

    <TypescriptOutDir>wwwroot</TypescriptOutDir>
    
  4. プロジェクト ファイルの PropertyGroup の内側に次のターゲットを追加して、TypeScript ターゲットを PrepareForBuildDependsOn ターゲットの依存関係として含めます。

    <PrepareForBuildDependsOn>
      CompileTypeScript;
      GetTypeScriptOutputForPublishing;$(PrepareForBuildDependsOn)
    </PrepareForBuildDependsOn>
    

参照されている RCL からコンテンツを使用する

RCL の wwwroot フォルダーに含まれるファイルは、_content/{PACKAGE ID}/ プレフィックスに基づいて RCL または使用アプリのいずれかに公開されます。 たとえば、アセンブリ名が Razor.Class.Lib で、そのプロジェクト ファイルに <PackageId> が指定されていないライブラリの場合、_content/Razor.Class.Lib/ の静的コンテンツへのパスが生成されます。 NuGet パッケージを生成するときに、アセンブリ名がパッケージ ID (ライブラリのプロジェクト ファイル内の<PackageId>) と異なる場合は、{PACKAGE ID} のプロジェクト ファイルで指定されているパッケージ ID を使用します。

使用アプリは、ライブラリによって提供される静的アセットを <script><style><img>、およびその他の HTML タグ付きで参照します。 使用アプリで、次のように静的ファイルのサポートが有効になっている必要があります。

var builder = WebApplication.CreateBuilder(args);

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

var app = builder.Build();

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

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

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.MapRazorPages();
app.Run();

使用アプリをビルド出力から実行 (dotnet run) すると、開発環境で、静的な Web アセットが既定で有効になります。 ビルド出力から実行するときに他の環境のアセットをサポートするには、Program.cs のホスト ビルダーで UseStaticWebAssets を呼び出します。

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.UseWebRoot("wwwroot");
builder.WebHost.UseStaticWebAssets();

builder.Services.AddRazorPages();

var app = builder.Build();

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

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

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

発行された出力からアプリを実行する (dotnet publish) 場合、UseStaticWebAssets の呼び出しは必要ありません。

複数プロジェクトの開発フロー

使用アプリの実行時は、次のようになります。

  • RCL のアセットは元のフォルダー内に保持されます。 これらのアセットは、使用アプリに移行されません。
  • RCL の wwwroot フォルダー内の変更は、使用アプリをリビルドしなくても、RCL がリビルドされた後で、使用アプリに反映されます。

RCL がビルドされると、静的な Web アセットの場所を記述するマニフェストが生成されます。 使用アプリは、実行時にそのマニフェストを読み取って、参照されているプロジェクトおよびパッケージのアセットを使用します。 RCL に新しいアセットが追加された場合は、使用アプリがその新しいアセットにアクセスする前に、RCL をリビルドしてそのマニフェストを更新する必要があります。

公開

アプリが公開されると、参照されているすべてのプロジェクトおよびパッケージのコンパニオン アセットが、_content/{PACKAGE ID}/ の下の公開済みアプリの wwwroot フォルダーにコピーされます。 NuGet パッケージを生成するときに、アセンブリ名がパッケージ ID (ライブラリのプロジェクト ファイル内の <PackageId>) と同じではない場合は、発行されたアセットの wwwroot フォルダーを調べるときに、{PACKAGE ID} のプロジェクト ファイルで指定されているパッケージ ID を使用します。

その他のリソース

Razor ビュー、ページ、コントローラー、ページ モデル、Razor コンポーネントビュー コンポーネント、データ モデルは、Razor クラス ライブラリ (RCL) に組み込むことが可能です。 RCL はパッケージ化し、再利用できます。 アプリケーションには RCL を含めることができます。また、それに含まれるビューやページをオーバーライドできます。 Web アプリと RCL の両方にビュー、部分ビュー、Razor ページがあるとき、Web アプリの Razor マークアップ ( .cshtml ファイル) が優先されます。

npm と webpack を Razor クラス ライブラリのビルド プロセスに統合する方法については、「Razor クラス ライブラリのクライアント Web アセットをビルドする」を参照してください。

Razor UI を含むクラス ライブラリの作成

  • Visual Studio から [新しいプロジェクトの作成] を選択します。
  • [Razor クラス ライブラリ]>[次へ] の順に選択します。
  • ライブラリに名前を付け (例: "RazorClassLib")、[作成] を選択します。 生成されたビュー ライブラリとファイル名の競合を避けるため、ライブラリ名の末尾が .Views ではないことを確認します。
  • ビューをサポートする必要がある場合は、 [ページとビューのサポート] を選択します。 既定では、Razor ページのみがサポートされています。 [作成] を選択します。

Razor クラス ライブラリ (RCL) テンプレートは Razor コンポーネント開発での既定です。 [ページとビューのサポート] オプションによって、ページとビューがサポートされます。

RCL に Razor ファイルを追加します。

ASP.NET Core テンプレートでは、RCL コンテンツが Areas フォルダーにあると見なされます。 ~/Areas/Pages ではなく ~/Pages でコンテンツを公開する RCL を作成する場合は、後述の「RCL ページのレイアウト」を参照してください。

RCL コンテンツを参照する

RCL は次によって参照できます。

ビュー、部分ビュー、ページのオーバーライド

Web アプリと RCL の両方にビュー、部分ビュー、Razor ページがある場合は、Web アプリの Razor マークアップ (.cshtml ファイル) が優先されます。 たとえば、WebApp1/Areas/MyFeature/Pages/Page1.cshtml を WebApp1 に追加すると、WebApp1 の Page1 は RCL の Page1 よりも優先されます。

サンプルのダウンロードで、WebApp1/Areas/MyFeature2 の名前を WebApp1/Areas/MyFeature に変更して、優先順位をテストします。

RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml 部分ビューを WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml にコピーします。 新しい場所を示すようにマークアップを更新します。 アプリをビルドして実行し、アプリの部分ビューが使用されていることを確認します。

RCL で Razor Pages を使用する場合は、ホスティング アプリで Razor Pages サービスとエンドポイントを有効にします。

var builder = WebApplication.CreateBuilder(args);

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

var app = builder.Build();

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

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

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.MapRazorPages();
app.Run();

RCL ページのレイアウト

RCL コンテンツを Web アプリの Pages フォルダーの一部であるかのように参照するには、次のファイル構造で RCL プロジェクトを作成します。

  • RazorUIClassLib/Pages
  • RazorUIClassLib/Pages/Shared

RazorUIClassLib/Pages/Shared に 2 つの部分ファイル (_Header.cshtml_Footer.cshtml) が含まれているとします。 これらの <partial> タグを _Layout.cshtml ファイルに追加できます。

<body>
  <partial name="_Header">
  @RenderBody()
  <partial name="_Footer">
</body>

_ViewStart.cshtml ファイルを、RCL プロジェクトの Pages フォルダーに追加して、ホスト Web アプリの _Layout.cshtml ファイルを使用します。

@{
    Layout = "_Layout";
}

静的アセットを含む RCL を作成する

RCL では、RCL または RCL の使用アプリで参照できる静的なコンパニオン アセットが必要になる場合があります。 ASP.NET Core では、使用アプリで利用できる静的アセットを含む RCL の作成が可能です。

コンパニオン アセットを RCL の一部として含めるには、クラス ライブラリに wwwroot フォルダーを作成し、必要なファイルをすべてそのフォルダーに含めます。

RCL をパックすると、wwwroot フォルダー内のすべてのコンパニオン アセットがパッケージに自動的に含まれます。

Nuget.exe バージョン nuget pack ではなく、dotnet pack コマンドを使用します。

静的アセットを除外する

静的アセットを除外するには、目的の除外パスをプロジェクトファイル内の $(DefaultItemExcludes) プロパティ グループに追加します。 各エントリは、セミコロン (;) で区切ります。

次の例では、wwwroot フォルダー内の lib.css スタイルシートが静的アセットとは見なされず、公開された RCL には含まれていません。

<PropertyGroup>
  <DefaultItemExcludes>$(DefaultItemExcludes);wwwroot\lib.css</DefaultItemExcludes>
</PropertyGroup>

Typescript の統合

TypeScript ファイルを RCL に含めるには、次の操作を行います。

  1. プロジェクトで Microsoft.TypeScript.MSBuild NuGet パッケージを参照します。

    Note

    .NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の "パッケージのインストールと管理" に関する記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。

  2. TypeScript ファイル (.ts) を wwwroot フォルダーの外側に配置します。 たとえば、ファイルを Client フォルダーに配置します。

  3. wwwroot フォルダーの TypeScript ビルド出力を構成します。 プロジェクト ファイルの PropertyGroup の内側に TypescriptOutDir プロパティを設定します。

    <TypescriptOutDir>wwwroot</TypescriptOutDir>
    
  4. プロジェクト ファイルの PropertyGroup の内側に次のターゲットを追加して、TypeScript ターゲットを PrepareForBuildDependsOn ターゲットの依存関係として含めます。

    <PrepareForBuildDependsOn>
      CompileTypeScript;
      GetTypeScriptOutputForPublishing;$(PrepareForBuildDependsOn)
    </PrepareForBuildDependsOn>
    

参照されている RCL からコンテンツを使用する

RCL の wwwroot フォルダーに含まれるファイルは、_content/{PACKAGE ID}/ プレフィックスに基づいて RCL または使用アプリのいずれかに公開されます。 たとえば、アセンブリ名が Razor.Class.Lib で、そのプロジェクト ファイルに <PackageId> が指定されていないライブラリの場合、_content/Razor.Class.Lib/ の静的コンテンツへのパスが生成されます。 NuGet パッケージを生成するときに、アセンブリ名がパッケージ ID (ライブラリのプロジェクト ファイル内の<PackageId>) と異なる場合は、{PACKAGE ID} のプロジェクト ファイルで指定されているパッケージ ID を使用します。

使用アプリは、ライブラリによって提供される静的アセットを <script><style><img>、およびその他の HTML タグ付きで参照します。 使用アプリで、次のように静的ファイルのサポートが有効になっている必要があります。

var builder = WebApplication.CreateBuilder(args);

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

var app = builder.Build();

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

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

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.MapRazorPages();
app.Run();

使用アプリをビルド出力から実行 (dotnet run) すると、開発環境で、静的な Web アセットが既定で有効になります。 ビルド出力から実行するときに他の環境のアセットをサポートするには、Program.cs のホスト ビルダーで UseStaticWebAssets を呼び出します。

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.UseWebRoot("wwwroot").UseStaticWebAssets();

builder.Services.AddRazorPages();

var app = builder.Build();

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

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

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

注: .NET 6 では builder.WebHost.UseWebRoot("wwwroot").UseStaticWebAssets の呼び出しのみが必要です。 詳細については、こちらの GitHub の問題のページを参照してください。

発行された出力からアプリを実行する (dotnet publish) 場合、UseStaticWebAssets の呼び出しは必要ありません。

複数プロジェクトの開発フロー

使用アプリの実行時は、次のようになります。

  • RCL のアセットは元のフォルダー内に保持されます。 これらのアセットは、使用アプリに移行されません。
  • RCL の wwwroot フォルダー内の変更は、使用アプリをリビルドしなくても、RCL がリビルドされた後で、使用アプリに反映されます。

RCL がビルドされると、静的な Web アセットの場所を記述するマニフェストが生成されます。 使用アプリは、実行時にそのマニフェストを読み取って、参照されているプロジェクトおよびパッケージのアセットを使用します。 RCL に新しいアセットが追加された場合は、使用アプリがその新しいアセットにアクセスする前に、RCL をリビルドしてそのマニフェストを更新する必要があります。

公開

アプリが公開されると、参照されているすべてのプロジェクトおよびパッケージのコンパニオン アセットが、_content/{PACKAGE ID}/ の下の公開済みアプリの wwwroot フォルダーにコピーされます。 NuGet パッケージを生成するときに、アセンブリ名がパッケージ ID (ライブラリのプロジェクト ファイル内の <PackageId>) と同じではない場合は、発行されたアセットの wwwroot フォルダーを調べるときに、{PACKAGE ID} のプロジェクト ファイルで指定されているパッケージ ID を使用します。

その他のリソース

Razor ビュー、ページ、コントローラー、ページ モデル、Razor コンポーネントビュー コンポーネント、データ モデルは、Razor クラス ライブラリ (RCL) に組み込むことが可能です。 RCL はパッケージ化し、再利用できます。 アプリケーションには RCL を含めることができます。また、それに含まれるビューやページをオーバーライドできます。 Web アプリと RCL の両方にビュー、部分ビュー、Razor ページがあるとき、Web アプリの Razor マークアップ ( .cshtml ファイル) が優先されます。

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

Razor UI を含むクラス ライブラリの作成

  • Visual Studio から [新しいプロジェクトの作成] を選択します。
  • [Razor クラス ライブラリ]>[次へ] の順に選択します。
  • ライブラリに名前を付け (例: "RazorClassLib")、[作成]>[次へ] の順に選択します。 生成されたビュー ライブラリとファイル名の競合を避けるため、ライブラリ名の末尾が .Views ではないことを確認します。
  • [ターゲット フレームワーク] を選択します。 ビューをサポートするための [☑ ページとビューのサポート] をチェックします。 既定では、Razor コンポーネントのみがサポートされています。 [作成] を選択します。

Razor クラス ライブラリ (RCL) テンプレートは Razor コンポーネント開発での既定です。 [ページとビューのサポート] オプションによって、ページとビューがサポートされます。

RCL に Razor ファイルを追加します。

ASP.NET Core テンプレートでは、RCL コンテンツが Areas フォルダーにあるものとしています。 ~/Areas/Pages ではなく ~/Pages でコンテンツを公開する RCL を作成する場合は、「RCL ページのレイアウト」を参照してください。

RCL コンテンツを参照する

RCL は次によって参照できます。

ビュー、部分ビュー、ページのオーバーライド

Web アプリと RCL の両方にビュー、部分ビュー、Razor ページがある場合は、Web アプリの Razor マークアップ (.cshtml ファイル) が優先されます。 たとえば、WebApp1/Areas/MyFeature/Pages/Page1.cshtml を WebApp1 に追加すると、WebApp1 の Page1 は RCL の Page1 よりも優先されます。

サンプルのダウンロードで、WebApp1/Areas/MyFeature2 の名前を WebApp1/Areas/MyFeature に変更して、優先順位をテストします。

RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml 部分ビューを WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml にコピーします。 新しい場所を示すようにマークアップを更新します。 アプリをビルドして実行し、アプリの部分ビューが使用されていることを確認します。

RCL ページのレイアウト

RCL コンテンツを Web アプリの Pages フォルダーの一部であるかのように参照するには、次のファイル構造で RCL プロジェクトを作成します。

  • RazorUIClassLib/Pages
  • RazorUIClassLib/Pages/Shared

RazorUIClassLib/Pages/Shared に 2 つの部分ファイル (_Header.cshtml_Footer.cshtml) が含まれているとします。 これらの <partial> タグを _Layout.cshtml ファイルに追加できます。

<body>
  <partial name="_Header">
  @RenderBody()
  <partial name="_Footer">
</body>

_ViewStart.cshtml ファイルを、RCL プロジェクトの Pages フォルダーに追加して、ホスト Web アプリの _Layout.cshtml ファイルを使用します。

@{
    Layout = "_Layout";
}

静的アセットを含む RCL を作成する

RCL では、RCL または RCL の使用アプリで参照できる静的なコンパニオン アセットが必要になる場合があります。 ASP.NET Core では、使用アプリで利用できる静的アセットを含む RCL の作成が可能です。

コンパニオン アセットを RCL の一部として含めるには、クラス ライブラリに wwwroot フォルダーを作成し、必要なファイルをすべてそのフォルダーに含めます。

RCL をパックすると、wwwroot フォルダー内のすべてのコンパニオン アセットがパッケージに自動的に含まれます。

Nuget.exe バージョン nuget pack ではなく、dotnet pack コマンドを使用します。

静的アセットを除外する

静的アセットを除外するには、目的の除外パスをプロジェクトファイル内の $(DefaultItemExcludes) プロパティ グループに追加します。 各エントリは、セミコロン (;) で区切ります。

次の例では、wwwroot フォルダー内の lib.css スタイルシートが静的アセットとは見なされず、公開された RCL には含まれていません。

<PropertyGroup>
  <DefaultItemExcludes>$(DefaultItemExcludes);wwwroot\lib.css</DefaultItemExcludes>
</PropertyGroup>

Typescript の統合

TypeScript ファイルを RCL に含めるには、次の操作を行います。

  1. プロジェクトで Microsoft.TypeScript.MSBuild NuGet パッケージを参照します。

    Note

    .NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の "パッケージのインストールと管理" に関する記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。

  2. TypeScript ファイル (.ts) を wwwroot フォルダーの外側に配置します。 たとえば、ファイルを Client フォルダーに配置します。

  3. wwwroot フォルダーの TypeScript ビルド出力を構成します。 プロジェクト ファイルの PropertyGroup の内側に TypescriptOutDir プロパティを設定します。

    <TypescriptOutDir>wwwroot</TypescriptOutDir>
    
  4. プロジェクト ファイルの PropertyGroup の内側に次のターゲットを追加して、TypeScript ターゲットを ResolveCurrentProjectStaticWebAssets ターゲットの依存関係として含めます。

    <ResolveCurrentProjectStaticWebAssetsInputsDependsOn>
      CompileTypeScript;
      $(ResolveCurrentProjectStaticWebAssetsInputs)
    </ResolveCurrentProjectStaticWebAssetsInputsDependsOn>
    

参照されている RCL からコンテンツを使用する

RCL の wwwroot フォルダーに含まれるファイルは、_content/{PACKAGE ID}/ プレフィックスに基づいて RCL または使用アプリのいずれかに公開されます。 たとえば、アセンブリ名が Razor.Class.Lib で、そのプロジェクト ファイルに <PackageId> が指定されていないライブラリの場合、_content/Razor.Class.Lib/ の静的コンテンツへのパスが生成されます。 NuGet パッケージを生成するときに、アセンブリ名がパッケージ ID (ライブラリのプロジェクト ファイル内の<PackageId>) と異なる場合は、{PACKAGE ID} のプロジェクト ファイルで指定されているパッケージ ID を使用します。

使用アプリは、ライブラリによって提供される静的アセットを <script><style><img>、およびその他の HTML タグ付きで参照します。 使用アプリの Startup.Configure静的ファイルのサポートが有効になっている必要があります。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    ...

    app.UseStaticFiles();

    ...
}

使用アプリをビルド出力から実行 (dotnet run) すると、開発環境で、静的な Web アセットが既定で有効になります。 ビルド出力から実行するときに他の環境のアセットをサポートするには、Program.cs のホスト ビルダーで UseStaticWebAssets を呼び出します。

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

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.UseStaticWebAssets();
                webBuilder.UseStartup<Startup>();
            });
}

発行された出力からアプリを実行する (dotnet publish) 場合、UseStaticWebAssets の呼び出しは必要ありません。

複数プロジェクトの開発フロー

使用アプリの実行時は、次のようになります。

  • RCL のアセットは元のフォルダー内に保持されます。 これらのアセットは、使用アプリに移行されません。
  • RCL の wwwroot フォルダー内の変更は、使用アプリをリビルドしなくても、RCL がリビルドされた後で、使用アプリに反映されます。

RCL がビルドされると、静的な Web アセットの場所を記述するマニフェストが生成されます。 使用アプリは、実行時にそのマニフェストを読み取って、参照されているプロジェクトおよびパッケージのアセットを使用します。 RCL に新しいアセットが追加された場合は、使用アプリがその新しいアセットにアクセスする前に、RCL をリビルドしてそのマニフェストを更新する必要があります。

公開

アプリが公開されると、参照されているすべてのプロジェクトおよびパッケージのコンパニオン アセットが、_content/{PACKAGE ID}/ の下の公開済みアプリの wwwroot フォルダーにコピーされます。 NuGet パッケージを生成するときに、アセンブリ名がパッケージ ID (ライブラリのプロジェクト ファイル内の <PackageId>) と同じではない場合は、発行されたアセットの wwwroot フォルダーを調べるときに、{PACKAGE ID} のプロジェクト ファイルで指定されているパッケージ ID を使用します。

その他のリソース

Razor ビュー、ページ、コントローラー、ページ モデル、Razor コンポーネントビュー コンポーネント、データ モデルは、Razor クラス ライブラリ (RCL) に組み込むことが可能です。 RCL はパッケージ化し、再利用できます。 アプリケーションには RCL を含めることができます。また、それに含まれるビューやページをオーバーライドできます。 Web アプリと RCL の両方にビュー、部分ビュー、Razor ページがあるとき、Web アプリの Razor マークアップ ( .cshtml ファイル) が優先されます。

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

Razor UI を含むクラス ライブラリの作成

  • Visual Studio の [ファイル] メニューから、[新規作成]>[プロジェクト] の順に選択します。
  • [ASP.NET Core Web アプリケーション] を選択します。
  • ライブラリに名前を付け (例: "RazorClassLib")、[OK] を選択します。 生成されたビュー ライブラリとファイル名の競合を避けるため、ライブラリ名の末尾が .Views ではないことを確認します。
  • ASP.NET Core 2.1 以降が選択されていることを確認します。
  • [Razor クラス ライブラリ]>[OK] の順に選択します。

RCL には次のプロジェクト ファイルがあります。

<Project Sdk="Microsoft.NET.Sdk.Razor">

    <PropertyGroup>
        <TargetFramework>netcoreapp3.1</TargetFramework>
        <AddRazorSupportForMvc>true</AddRazorSupportForMvc>
    </PropertyGroup>

    <ItemGroup>
        <FrameworkReference Include="Microsoft.AspNetCore.App" />
    </ItemGroup>


</Project>

RCL に Razor ファイルを追加します。

ASP.NET Core テンプレートでは、RCL コンテンツが Areas フォルダーにあるものとしています。 ~/Areas/Pages ではなく ~/Pages でコンテンツを公開する RCL を作成する場合は、「RCL ページのレイアウト」を参照してください。

RCL コンテンツを参照する

RCL は次によって参照できます。

チュートリアル: RCL プロジェクトを作成し、Razor Pages プロジェクトから使用する

作成しなくても、完全なプロジェクトをダウンロードしてテストできます。 サンプル ダウンロードには、プロジェクトのテストを簡単にする追加のコードやリンクが含まれています。 GitHub の問題に関するフィードバックはこちらで扱っています。ダウンロード サンプルと段階的指示の違いについてコメントを投稿できます。

ダウンロード アプリをテストする

完全なアプリをダウンロードしておらず、チュートリアル プロジェクトを作成する場合、次のセクションに進んでください。

Visual Studio で .sln ファイルを開きます。 アプリを実行します。

テスト WebApp1 の指示に従ってください。

RCL を作成する

このセクションでは、RCL が作成されます。 Razor ファイルが RCL に追加されます。

RCL プロジェクトの作成:

  • Visual Studio の [ファイル] メニューから、[新規作成]>[プロジェクト] の順に選択します。
  • [ASP.NET Core Web アプリケーション] を選択します。
  • アプリに RazorUIClassLib という名前を付け、[OK] を選択します。
  • ASP.NET Core 2.1 以降が選択されていることを確認します。
  • [Razor クラス ライブラリ]>[OK] の順に選択します。
  • RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml という名前の Razor 部分ビュー ファイルを追加します。

Razor ファイルとフォルダーをプロジェクトに追加する

  • RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml のマークアップを次のコードに変更します。

    <h3>_Message.cshtml partial view.</h3>
    
    <p>RazorUIClassLib\Areas\MyFeature\Pages\Shared\_Message.cshtml</p>
    
  • RazorUIClassLib/Areas/MyFeature/Pages/Page1.cshtml のマークアップを次のコードに変更します。

    @page
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    
    <h2>Hello from a Razor UI class library!</h2>
    <p> From  RazorUIClassLib\Areas\MyFeature\Pages\Page1.cshtml</p>
    
    <partial name="_Message" />
    

    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers は部分ビュー (<partial name="_Message" />) を使用するために必要です。 @addTagHelper ディレクティブを含める代わりに、 _ViewImports.cshtml ファイルを追加できます。 次に例を示します。

    dotnet new viewimports -o RazorUIClassLib/Areas/MyFeature/Pages
    

    _ViewImports.cshtml の詳細については、「共有ディレクティブのインポート」を参照してください

  • クラス ライブラリをビルドし、コンパイラ エラーがないことを確認します。

    dotnet build RazorUIClassLib
    

ビルド出力には RazorUIClassLib.dllRazorUIClassLib.Views.dll が含まれています。 RazorUIClassLib.Views.dll には、コンパイル済みの Razor コンテンツが含まれています。

Razor ページ プロジェクトから Razor UI ライブラリを使用します。

Razor ページ Web アプリの作成:

  • ソリューション エクスプローラーで、ソリューションを右クリックし、[追加]>[新しいプロジェクト] の順に選択します。

  • [ASP.NET Core Web アプリケーション] を選択します。

  • アプリに WebApp1 という名前を付けます。

  • ASP.NET Core 2.1 以降が選択されていることを確認します。

  • [Web アプリケーション][OK] の順に選択します。

  • ソリューション エクスプローラーで、WebApp1 を右クリックし、 [スタートアップ プロジェクトに設定] を選択します。

  • ソリューション エクスプローラーで、WebApp1 を右クリックし、[ビルド依存関係][プロジェクトの依存関係] の順に選択します。

  • WebApp1 の依存関係として RazorUIClassLib を選択します。

  • ソリューション エクスプローラーで、WebApp1 を右クリックし、[追加][参照] の順に選択します。

  • [参照マネージャー] ダイアログで、[RazorUIClassLib] をオンにし、[OK] を選択します。

アプリケーションを実行します。

テスト WebApp1

/MyFeature/Page1 を参照して、Razor UI クラス ライブラリが使用されていることを確認します。

ビュー、部分ビュー、ページのオーバーライド

Web アプリと RCL の両方にビュー、部分ビュー、Razor ページがある場合は、Web アプリの Razor マークアップ (.cshtml ファイル) が優先されます。 たとえば、WebApp1/Areas/MyFeature/Pages/Page1.cshtml を WebApp1 に追加すると、WebApp1 の Page1 は RCL の Page1 よりも優先されます。

サンプルのダウンロードで、WebApp1/Areas/MyFeature2 の名前を WebApp1/Areas/MyFeature に変更して、優先順位をテストします。

RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml 部分ビューを WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml にコピーします。 新しい場所を示すようにマークアップを更新します。 アプリをビルドして実行し、アプリの部分ビューが使用されていることを確認します。

RCL ページのレイアウト

RCL コンテンツを Web アプリの Pages フォルダーの一部であるかのように参照するには、次のファイル構造で RCL プロジェクトを作成します。

  • RazorUIClassLib/Pages
  • RazorUIClassLib/Pages/Shared

RazorUIClassLib/Pages/Shared に 2 つの部分ファイル (_Header.cshtml_Footer.cshtml) が含まれているとします。 これらの <partial> タグを _Layout.cshtml ファイルに追加できます。

<body>
  <partial name="_Header">
  @RenderBody()
  <partial name="_Footer">
</body>

Razor ビュー、ページ、コントローラー、ページ モデル、Razor コンポーネントビュー コンポーネント、データ モデルは、Razor クラス ライブラリ (RCL) に組み込むことが可能です。 RCL はパッケージ化し、再利用できます。 アプリケーションには RCL を含めることができます。また、それに含まれるビューやページをオーバーライドできます。 Web アプリと RCL の両方にビュー、部分ビュー、Razor ページがあるとき、Web アプリの Razor マークアップ ( .cshtml ファイル) が優先されます。

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

Razor UI を含むクラス ライブラリの作成

  • Visual Studio から [新しいプロジェクトの作成] を選択します。
  • [Razor クラス ライブラリ]>[次へ] の順に選択します。
  • ライブラリに名前を付け (例: "RazorClassLib")、[作成] を選択します。 生成されたビュー ライブラリとファイル名の競合を避けるため、ライブラリ名の末尾が .Views ではないことを確認します。
  • ビューをサポートする必要がある場合は、 [ページとビューのサポート] を選択します。 既定では、Razor ページのみがサポートされています。 [作成] を選択します。

Razor クラス ライブラリ (RCL) テンプレートは Razor コンポーネント開発での既定です。 [ページとビューのサポート] オプションによって、ページとビューがサポートされます。

RCL に Razor ファイルを追加します。

ASP.NET Core テンプレートでは、RCL コンテンツが Areas フォルダーにあると見なされます。 ~/Areas/Pages ではなく ~/Pages でコンテンツを公開する RCL を作成する場合は、後述の「RCL ページのレイアウト」を参照してください。

RCL コンテンツを参照する

RCL は次によって参照できます。

ビュー、部分ビュー、ページのオーバーライド

Web アプリと RCL の両方にビュー、部分ビュー、Razor ページがある場合は、Web アプリの Razor マークアップ (.cshtml ファイル) が優先されます。 たとえば、WebApp1/Areas/MyFeature/Pages/Page1.cshtml を WebApp1 に追加すると、WebApp1 の Page1 は RCL の Page1 よりも優先されます。

サンプルのダウンロードで、WebApp1/Areas/MyFeature2 の名前を WebApp1/Areas/MyFeature に変更して、優先順位をテストします。

RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml 部分ビューを WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml にコピーします。 新しい場所を示すようにマークアップを更新します。 アプリをビルドして実行し、アプリの部分ビューが使用されていることを確認します。

RCL で Razor Pages を使用する場合は、ホスティング アプリで Razor Pages サービスとエンドポイントを有効にします。

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

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles();
    app.UseRouting();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");

        endpoints.MapRazorPages();
    });
}

RCL ページのレイアウト

RCL コンテンツを Web アプリの Pages フォルダーの一部であるかのように参照するには、次のファイル構造で RCL プロジェクトを作成します。

  • RazorUIClassLib/Pages
  • RazorUIClassLib/Pages/Shared

RazorUIClassLib/Pages/Shared に 2 つの部分ファイル (_Header.cshtml_Footer.cshtml) が含まれているとします。 これらの <partial> タグを _Layout.cshtml ファイルに追加できます。

<body>
  <partial name="_Header">
  @RenderBody()
  <partial name="_Footer">
</body>

_ViewStart.cshtml ファイルを、RCL プロジェクトの Pages フォルダーに追加して、ホスト Web アプリの _Layout.cshtml ファイルを使用します。

@{
    Layout = "_Layout";
}

静的アセットを含む RCL を作成する

RCL では、RCL または RCL の使用アプリで参照できる静的なコンパニオン アセットが必要になる場合があります。 ASP.NET Core では、使用アプリで利用できる静的アセットを含む RCL の作成が可能です。

コンパニオン アセットを RCL の一部として含めるには、クラス ライブラリに wwwroot フォルダーを作成し、必要なファイルをすべてそのフォルダーに含めます。

RCL をパックすると、wwwroot フォルダー内のすべてのコンパニオン アセットがパッケージに自動的に含まれます。

Nuget.exe バージョン nuget pack ではなく、dotnet pack コマンドを使用します。

静的アセットを除外する

静的アセットを除外するには、目的の除外パスをプロジェクトファイル内の $(DefaultItemExcludes) プロパティ グループに追加します。 各エントリは、セミコロン (;) で区切ります。

次の例では、wwwroot フォルダー内の lib.css スタイルシートが静的アセットとは見なされず、公開された RCL には含まれていません。

<PropertyGroup>
  <DefaultItemExcludes>$(DefaultItemExcludes);wwwroot\lib.css</DefaultItemExcludes>
</PropertyGroup>

Typescript の統合

TypeScript ファイルを RCL に含めるには、次の操作を行います。

  1. プロジェクトで Microsoft.TypeScript.MSBuild NuGet パッケージを参照します。

    Note

    .NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の "パッケージのインストールと管理" に関する記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。

  2. TypeScript ファイル (.ts) を wwwroot フォルダーの外側に配置します。 たとえば、ファイルを Client フォルダーに配置します。

  3. wwwroot フォルダーの TypeScript ビルド出力を構成します。 プロジェクト ファイルの PropertyGroup の内側に TypescriptOutDir プロパティを設定します。

    <TypescriptOutDir>wwwroot</TypescriptOutDir>
    
  4. プロジェクト ファイルの PropertyGroup の内側に次のターゲットを追加して、TypeScript ターゲットを ResolveCurrentProjectStaticWebAssets ターゲットの依存関係として含めます。

    <ResolveCurrentProjectStaticWebAssetsInputsDependsOn>
      CompileTypeScript;
      $(ResolveCurrentProjectStaticWebAssetsInputs)
    </ResolveCurrentProjectStaticWebAssetsInputsDependsOn>
    

参照されている RCL からコンテンツを使用する

RCL の wwwroot フォルダーに含まれるファイルは、_content/{PACKAGE ID}/ プレフィックスに基づいて RCL または使用アプリのいずれかに公開されます。 たとえば、アセンブリ名が Razor.Class.Lib で、そのプロジェクト ファイルに <PackageId> が指定されていないライブラリの場合、_content/Razor.Class.Lib/ の静的コンテンツへのパスが生成されます。 NuGet パッケージを生成するときに、アセンブリ名がパッケージ ID (ライブラリのプロジェクト ファイル内の<PackageId>) と異なる場合は、{PACKAGE ID} のプロジェクト ファイルで指定されているパッケージ ID を使用します。

使用アプリは、ライブラリによって提供される静的アセットを <script><style><img>、およびその他の HTML タグ付きで参照します。 使用アプリの Startup.Configure静的ファイルのサポートが有効になっている必要があります。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    ...

    app.UseStaticFiles();

    ...
}

使用アプリをビルド出力から実行 (dotnet run) すると、開発環境で、静的な Web アセットが既定で有効になります。 ビルド出力から実行するときに他の環境のアセットをサポートするには、Program.cs のホスト ビルダーで UseStaticWebAssets を呼び出します。

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

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.UseStaticWebAssets();
                webBuilder.UseStartup<Startup>();
            });
}

発行された出力からアプリを実行する (dotnet publish) 場合、UseStaticWebAssets の呼び出しは必要ありません。

複数プロジェクトの開発フロー

使用アプリの実行時は、次のようになります。

  • RCL のアセットは元のフォルダー内に保持されます。 これらのアセットは、使用アプリに移行されません。
  • RCL の wwwroot フォルダー内の変更は、使用アプリをリビルドしなくても、RCL がリビルドされた後で、使用アプリに反映されます。

RCL がビルドされると、静的な Web アセットの場所を記述するマニフェストが生成されます。 使用アプリは、実行時にそのマニフェストを読み取って、参照されているプロジェクトおよびパッケージのアセットを使用します。 RCL に新しいアセットが追加された場合は、使用アプリがその新しいアセットにアクセスする前に、RCL をリビルドしてそのマニフェストを更新する必要があります。

公開

アプリが公開されると、参照されているすべてのプロジェクトおよびパッケージのコンパニオン アセットが、_content/{PACKAGE ID}/ の下の公開済みアプリの wwwroot フォルダーにコピーされます。 NuGet パッケージを生成するときに、アセンブリ名がパッケージ ID (ライブラリのプロジェクト ファイル内の <PackageId>) と同じではない場合は、発行されたアセットの wwwroot フォルダーを調べるときに、{PACKAGE ID} のプロジェクト ファイルで指定されているパッケージ ID を使用します。

その他のリソース