次の方法で共有


ASP.NET Core Razor コンポーネントを Razor クラス ライブラリ (RCL) から使用する

注意

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

警告

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

重要

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

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

コンポーネントは、プロジェクト間で Razor クラス ライブラリ (RCL) で共有できます。 次のものからのコンポーネントと静的アセットをアプリに含めます。

  • ソリューションの別のプロジェクト。
  • 参照されている .NET ライブラリ。
  • NuGet パッケージ。

コンポーネントが通常の .NET 型であるのと同様に、RCL によって提供されるコンポーネントは通常の .NET アセンブリです。

RCL を作成する

  1. 新しいプロジェクトを作成します。
  2. [新しいプロジェクトの作成] ダイアログで、ASP.NET Core プロジェクト テンプレートの一覧から [Razor クラス ライブラリ] を選択します。 [次へ] を選択します。
  3. [新しいプロジェクトを構成します] ダイアログで、[プロジェクト名] フィールドにプロジェクト名を入力します。 このトピックの例では、プロジェクト名 ComponentLibrary を使用します。 [次へ] を選択します。
  4. [追加情報] ダイアログでは、[サポート ページとビュー] は選択しないでください。 [作成] を選択します
  5. RCL をソリューションに追加します。
    1. ソリューションを開きます。
    2. ソリューション エクスプローラーでソリューションを右クリックします。 [追加]>[既存のプロジェクト] を選択します。
    3. RCL のプロジェクト ファイルに移動します。
    4. RCL のプロジェクト ファイル (.csproj) を選択します。
  6. アプリから RCL への参照を追加します。
    1. アプリ プロジェクトを右クリックします。 [追加]>[プロジェクト参照] を選択します。
    2. RCL プロジェクトを選択します。 [OK] を選択します。

RCL からの Razor コンポーネントを使用する

RCL からのコンポーネントを別のプロジェクトで使用するには、次のいずれかの方法を使用します。

  • RCL の名前空間を含む完全なコンポーネントの種類名を使用します。
  • Razor の @using ディレクティブで RCL の名前空間が宣言されている場合、個々のコンポーネントを RCL の名前空間なしで名前で追加することができます。 次の方法を使用します。
    • 個々のコンポーネントに @using ディレクティブを追加します。
    • プロジェクト全体でライブラリのコンポーネントを使用できるようにするには、最上位の _Imports.razor ファイルに @using ディレクティブを含めます。 ディレクティブを任意のレベルの _Imports.razor ファイルに追加して、名前空間をフォルダー内の 1 つのコンポーネントまたは複数のコンポーネントに適用します。 _Imports.razor ファイルを使用する場合、個々のコンポーネントに RCL の名前空間のための @using ディレクティブは必要ありません。

次の例で、ComponentLibraryComponent1 コンポーネントを含む RCL です。 Component1 コンポーネントは、ページとビューをサポートするために作成されていない RCL プロジェクト テンプレートから作成された RCL に自動的に追加されるコンポーネントの例です。

ComponentLibrary RCL の Component1.razor:

<div class="my-component">
    This component is defined in the <strong>ComponentLibrary</strong> package.
</div>

RCL を使用するアプリでは、次の例に示すように、名前空間を使用して Component1 コンポーネントを参照します。

ConsumeComponent1.razor:

@page "/consume-component-1"

<h1>Consume component (full namespace example)</h1>

<ComponentLibrary.Component1 />

または、@using ディレクティブを追加し、名前空間なしでコンポーネントを使用します。 次の @using ディレクティブは、現在のフォルダー内またはその上の任意の _Imports.razor ファイルにあっても構いません。

ConsumeComponent2.razor:

@page "/consume-component-2"
@using ComponentLibrary

<h1>Consume component (<code>@@using</code> example)</h1>

<Component1 />

CSS の分離を使用するライブラリ コンポーネントの場合、コンポーネント スタイルは、使用アプリで自動的に利用できるようになります。 ライブラリが使用されるアプリで、ライブラリの個々のコンポーネントのスタイルシートまたはバンドルされている CSS ファイルを手動でリンクまたはインポートする必要はありません。 アプリは、RCL のバンドルされたスタイルを参照するのに、CSS インポートを使用します。 バンドルされたスタイルは、そのライブラリを使用するアプリの静的な Web アセットとして公開されません。 ClassLib という名前のクラス ライブラリと、BlazorSample.styles.css というスタイルシートがある Blazor アプリでは、アプリのスタイルシートの一番上に RCL のスタイルシートが、ビルド時に自動的にインポートされます。

@import '_content/ClassLib/ClassLib.bundle.scp.css';

前の例で、Component1 のスタイルシート (Component1.razor.css) は自動的にバンドルされています。

ComponentLibrary RCL の Component1.razor.css:

.my-component {
    border: 2px dashed red;
    padding: 1em;
    margin: 1em 0;
    background-image: url('background.png');
}

背景画像も RCL プロジェクト テンプレートから組み込まれ、RCL の wwwroot フォルダーに格納されています。

ComponentLibrary RCL の wwwroot/background.png:

RCL プロジェクト テンプレートからの斜めストライプの背景画像

ライブラリの wwwroot フォルダーのスタイルシートから追加のライブラリ コンポーネント スタイルを提供するには、次の例が示すように、RCL コンシューマーにスタイルシート <link> タグを追加します。

重要

一般に、ライブラリ コンポーネントでは、CSS 分離を使用してコンポーネント スタイルをバンドルし、提供します。 CSS 分離に依存するコンポーネント スタイルは、RCL を使用するアプリで自動的に使用できます。 ライブラリが使用されるアプリで、ライブラリの個々のコンポーネントのスタイルシートまたはバンドルされている CSS ファイルを手動でリンクまたはインポートする必要はありません。 次の例では、"CSS 分離の外" でグローバル スタイルシートを提供します。これは通常、RCL を使用する一般的なアプリの要件ではありません。

次の例では、以下の背景画像が使用されています。 このセクションに示されている例を実装する場合は、画像を右クリックしてローカルに保存します。

ComponentLibrary RCL の wwwroot/extra-background.png:

開発者によってライブラリに追加された斜めストライプの背景画像

extra-style クラスを持つ RCL に新しいスタイルシートを追加します。

ComponentLibrary RCL の wwwroot/additionalStyles.css:

.extra-style {
    border: 2px dashed blue;
    padding: 1em;
    margin: 1em 0;
    background-image: url('extra-background.png');
}

extra-style クラスを使用するコンポーネントを RCL に追加します。

ComponentLibrary RCL の ExtraStyles.razor:

<div class="extra-style">
    <p>
        This component is defined in the <strong>ComponentLibrary</strong> package.
    </p>
</div>

RCL の ExtraStyles コンポーネントを使用するアプリにページを追加します。

ConsumeComponent3.razor:

@page "/consume-component-3"
@using ComponentLibrary

<h1>Consume component (<code>additionalStyles.css</code> example)</h1>

<ExtraStyles />

アプリの <head> マークアップ内でライブラリのスタイルシートにリンクします (<head> コンテンツの場所)。

Blazor Web Apps:

<link href="@Assets["_content/ComponentLibrary/additionalStyles.css"]" rel="stylesheet">

スタンドアロン Blazor WebAssembly アプリ:

<link href="_content/ComponentLibrary/additionalStyles.css" rel="stylesheet">
<link href="_content/ComponentLibrary/additionalStyles.css" rel="stylesheet">

CSS の分離を使用するライブラリ コンポーネントの場合、コンポーネント スタイルは、使用アプリで自動的に利用できるようになります。 ライブラリが使用されるアプリで、ライブラリの個々のコンポーネントのスタイルシートまたはバンドルされている CSS ファイルを手動でリンクまたはインポートする必要はありません。 アプリは、RCL のバンドルされたスタイルを参照するのに、CSS インポートを使用します。 バンドルされたスタイルは、そのライブラリを使用するアプリの静的な Web アセットとして公開されません。 ClassLib という名前のクラス ライブラリと、BlazorSample.styles.css というスタイルシートがある Blazor アプリでは、アプリのスタイルシートの一番上に RCL のスタイルシートが、ビルド時に自動的にインポートされます。

@import '_content/ClassLib/ClassLib.bundle.scp.css';

前の例で、Component1 のスタイルシート (Component1.razor.css) は自動的にバンドルされています。

ComponentLibrary RCL の Component1.razor.css:

.my-component {
    border: 2px dashed red;
    padding: 1em;
    margin: 1em 0;
    background-image: url('background.png');
}

背景画像も RCL プロジェクト テンプレートから組み込まれ、RCL の wwwroot フォルダーに格納されています。

ComponentLibrary RCL の wwwroot/background.png:

RCL プロジェクト テンプレートからの斜めストライプの背景画像

次の背景画像とスタイルシートは、RCL の Component1 サンプル コンポーネントによって使用されます。 これらの静的アセットは、プロジェクト テンプレートによって自動的に追加されるため、RCL プロジェクト テンプレートから作成された新しい RCL に追加する必要はありません。

ComponentLibrary RCL の wwwroot/background.png:

RCL プロジェクト テンプレートによってライブラリに追加された斜めストライプの背景画像

ComponentLibrary RCL の wwwroot/styles.css:

.my-component {
    border: 2px dashed red;
    padding: 1em;
    margin: 1em 0;
    background-image: url('background.png');
}

Component1my-component CSS クラスを提供するには、アプリの <head> マークアップ内でライブラリのスタイルシートにリンクします (<head>コンテンツの場所)。

<link href="_content/ComponentLibrary/styles.css" rel="stylesheet" />

ルーティング可能なコンポーネントを RCL から利用できるようにする

RCL 内のルーティング可能なコンポーネントを直接要求に使用できるようにするには、RCL のアセンブリをアプリのルーターに公開する必要があります。

アプリの App コンポーネント (App.razor) を開きます。 Assembly コレクションを Router コンポーネントの AdditionalAssemblies パラメータに割り当てて、RCL のアセンブリを含めます。 次の例では、ComponentLibrary.Component1 コンポーネントは RCL のアセンブリを検出する目的で使用されます。

AdditionalAssemblies="new[] { typeof(ComponentLibrary.Component1).Assembly }"

詳細については、「ASP.NET Core の Blazor ルーティングとナビゲーション」を参照してください。

静的アセットを含む RCL を wwwroot フォルダーに作成する

RCL の静的アセットは、ライブラリを使用するすべてのアプリで使用できます。

RCL の wwwroot フォルダーに静的アセットを配置し、アプリで _content/{PACKAGE ID}/{PATH AND FILE NAME} のパスを使用して静的アセットを参照します。 {PACKAGE ID} プレースホルダーは、ライブラリのパッケージ ID です。 プロジェクト ファイルで <PackageId> が指定されていない場合、パッケージ ID の既定値はプロジェクトのアセンブリ名になります。 {PATH AND FILE NAME} プレースホルダーは、wwwroot の下のパスとファイル名です。 このパス形式はアプリで、RCL に追加された NuGet パッケージによって提供される静的資産についても使用します。

次の例では、ComponentLibrary という名前の RCL と、RCL を使用する Blazor アプリを使用して RCL 静的アセットを使用する方法を示します。 アプリには、ComponentLibrary RCL に対するプロジェクト参照があります。

このセクションの例では、次の Jeep® の画像を使用します。 このセクションに示されている例を実装する場合は、画像を右クリックしてローカルに保存します。

ComponentLibrary RCL の wwwroot/jeep-yj.png:

Jeep YJ®

次の JeepYJ コンポーネントを RCL に追加します。

ComponentLibrary RCL の JeepYJ.razor:

<h3>ComponentLibrary.JeepYJ</h3>

<p>
    <img alt="Jeep YJ&reg;" src="_content/ComponentLibrary/jeep-yj.png" />
</p>

ComponentLibrary RCL を使用するアプリに次の Jeep コンポーネントを追加します。 Jeep コンポーネントでは次のものが使用されています。

  • ComponentLibrary RCL の wwwroot フォルダーにある Jeep YJ® の画像。
  • RCL にある JeepYJ コンポーネント。

Jeep.razor:

@page "/jeep"
@using ComponentLibrary

<div style="float:left;margin-right:10px">
    <h3>Direct use</h3>

    <p>
        <img alt="Jeep YJ&reg;" src="_content/ComponentLibrary/jeep-yj.png" />
    </p>
</div>

<JeepYJ />

<p>
    <em>Jeep</em> and <em>Jeep YJ</em> are registered trademarks of 
    <a href="https://www.stellantis.com">FCA US LLC (Stellantis NV)</a>.
</p>

レンダリングされた Jeep コンポーネント:

Jeep コンポーネント

詳しくは、「ASP.NET Core のクラス ライブラリの再利用可能 Razor UI」をご覧ください。

コンポーネントと併置される JavaScript ファイルを含む RCL を作成する

Razor コンポーネントの JavaScript (JS) ファイルの併置は、アプリでスクリプトを整理する便利な方法です。

Blazor アプリの Razor コンポーネントは、.razor.js 拡張子を使って JS ファイルを併置し、プロジェクト内のファイルへのパスを使ってパブリックにアドレス指定できます。

{PATH}/{COMPONENT}.razor.js

  • {PATH} プレースホルダーは、コンポーネントへのパスです。
  • {COMPONENT} プレースホルダーはコンポーネントです。

アプリが公開されると、スクリプトはフレームワークによって Web ルートに自動的に移動されます。 スクリプトは、bin/Release/{TARGET FRAMEWORK MONIKER}/publish/wwwroot/{PATH}/{COMPONENT}.razor.js に移動されます。プレースホルダーの内容は次のとおりです。

公開される静的資産への JS ファイルの配置は Blazor によって自動的に処理されるので、スクリプトの相対 URL を変更する必要はありません。

このセクションと以下の例では、主に JS ファイルの併置について説明することに重点を置きます。 最初に、通常の JS 関数で併置される JS ファイルの例を示します。 次に、モジュールを使って関数を読み込む例を示します。これは、ほとんどの運用アプリに推奨されるアプローチです。 .NET からの JS の呼び出しについては「ASP.NET Core Blazor で .NET メソッドから JavaScript 関数を呼び出す」で詳細に説明されており、そこに BlazorJS API のさらに詳しい説明と他の例があります。 2 番目の例で示されているコンポーネントの破棄については、「ASP.NET Core Razor コンポーネントのライフサイクル」で説明されています。

次の JsCollocation1 コンポーネントでは、HeadContent コンポーネントを介してスクリプトを読み込み、IJSRuntime.InvokeAsync を使って JS 関数を呼び出しています。 {PATH} プレースホルダーは、コンポーネントへのパスです。

重要

テスト アプリで実際に次のコードを使ってみる場合は、{PATH} プレースホルダーをコンポーネントのパスに変更してください (例: .NET 8 以降の場合は Components/Pages、.NET 7 以前の場合は Pages)。 Blazor Web App (.NET 8 以降) のコンポーネントでは、対話型レンダリング モードを、アプリにグローバルに適用するか、コンポーネント定義に適用する必要があります。

Blazor スクリプト (Blazor 開始スクリプトの場所) の後に次のスクリプトを追加します。

<script src="{PATH}/JsCollocation1.razor.js"></script>

JsCollocation1 コンポーネント ({PATH}/JsCollocation1.razor):

@page "/js-collocation-1"
@inject IJSRuntime JS

<PageTitle>JS Collocation 1</PageTitle>

<h1>JS Collocation Example 1</h1>

<button @onclick="ShowPrompt">Call showPrompt1</button>

@if (!string.IsNullOrEmpty(result))
{
    <p>
        Hello @result!
    </p>
}

@code {
    private string? result;

    public async Task ShowPrompt()
    {
        result = await JS.InvokeAsync<string>(
            "showPrompt1", "What's your name?");
        StateHasChanged();
    }
}

併置される JS ファイルは、JsCollocation1.razor.js というファイル名で JsCollocation1 コンポーネント ファイルに隣接して配置されます。 JsCollocation1 コンポーネント内では、スクリプトは併置されたファイルのパスで参照されます。 次の例の showPrompt1 関数は、Window prompt() からユーザーの名前を受け取り、それを表示するために JsCollocation1 コンポーネントに返します。

{PATH}/JsCollocation1.razor.js:

function showPrompt1(message) {
  return prompt(message, 'Type your name here');
}

上記の方法は、グローバル関数でクライアントを汚染するため、運用アプリでの一般的な使用には推奨されません。 運用アプリのためのさらに優れたアプローチは、JS モジュールを使うことです。 次の例で示すように、併置された JS ファイルからの JS モジュールの読み込みにも同じ一般的な原則が適用されます。

次の JsCollocation2 コンポーネントの OnAfterRenderAsync メソッドは、コンポーネント クラスの IJSObjectReference である moduleに JS モジュールを読み込みます。 module は、showPrompt2 関数を呼び出すために使われます。 {PATH} プレースホルダーは、コンポーネントへのパスです。

重要

テスト アプリで実際に次のコードを使ってみる場合は、{PATH} プレースホルダーをコンポーネントのパスに変更してください。 Blazor Web App (.NET 8 以降) のコンポーネントでは、対話型レンダリング モードを、アプリにグローバルに適用するか、コンポーネント定義に適用する必要があります。

JsCollocation2 コンポーネント ({PATH}/JsCollocation2.razor):

@page "/js-collocation-2"
@implements IAsyncDisposable
@inject IJSRuntime JS

<PageTitle>JS Collocation 2</PageTitle>

<h1>JS Collocation Example 2</h1>

<button @onclick="ShowPrompt">Call showPrompt2</button>

@if (!string.IsNullOrEmpty(result))
{
    <p>
        Hello @result!
    </p>
}

@code {
    private IJSObjectReference? module;
    private string? result;

    protected async override Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            /*
                Change the {PATH} placeholder in the next line to the path of
                the collocated JS file in the app. Examples:

                ./Components/Pages/JsCollocation2.razor.js (.NET 8 or later)
                ./Pages/JsCollocation2.razor.js (.NET 7 or earlier)
            */
            module = await JS.InvokeAsync<IJSObjectReference>("import",
                "./{PATH}/JsCollocation2.razor.js");
        }
    }

    public async void ShowPrompt()
    {
        if (module is not null)
        {
            result = await module.InvokeAsync<string>(
                "showPrompt2", "What's your name?");
            StateHasChanged();
        }
    }

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (module is not null)
        {
            try
            {
                await module.DisposeAsync();
            }
            catch (JSDisconnectedException)
            {
            }
        }
    }
}

前の例では、BlazorのSignalR回路が失われた場合に、モジュールの破棄中にJSDisconnectedExceptionがトラップされます。 上記のコードが Blazor WebAssembly アプリで使用されている場合、失われる SignalR 接続がないため、 try-catch ブロックを削除し、モジュールを破棄する行 (await module.DisposeAsync();) のままにすることができます。 詳しくは、「ASP.NET Core Blazor JavaScript の相互運用性 (JS 相互運用)」をご覧ください。

{PATH}/JsCollocation2.razor.js:

export function showPrompt2(message) {
  return prompt(message, 'Type your name here');
}

Razor クラス ライブラリ (RCL) での併置された JS に対するスクリプトとモジュールの使用は、IJSRuntime インターフェイスに基づく Blazor の JS 相互運用メカニズムでのみサポートされます。 JavaScript [JSImport]/[JSExport] 相互運用を実装する場合は、「ASP.NET Core Blazor を使用した JavaScript JSImport/JSExport の相互運用」をご覧ください。

IJSRuntime ベースの JS 相互運用を使用して Razor クラス ライブラリ (RCL) によって提供されるスクリプトまたはモジュールの場合は、次のパスが使われます。

./_content/{PACKAGE ID}/{PATH}/{COMPONENT}.{EXTENSION}.js

  • JS ファイルへの正しい静的アセット パスを作成するためには、現在のディレクトリ (./) に対するパス セグメントが必要です。
  • {PACKAGE ID} プレースホルダーは、RCL のパッケージ識別子 (または、アプリによって参照されるクラス ライブラリのライブラリ名) です。
  • {PATH} プレースホルダーは、コンポーネントへのパスです。 Razor コンポーネントが RCL のルートにある場合、パス セグメントは含まれません。
  • {COMPONENT} プレースホルダーはコンポーネント名です。
  • {EXTENSION} プレースホルダーは、コンポーネントの拡張子 (razor または cshtml) と一致します。

次の Blazor アプリの例の場合:

  • RCL のパッケージ識別子は AppJS です。
  • モジュールのスクリプトは、JsCollocation3 コンポーネント (JsCollocation3.razor) に対して読み込まれます。
  • JsCollocation3 コンポーネントは、RCL の Components/Pages フォルダーにあります。
module = await JS.InvokeAsync<IJSObjectReference>("import", 
    "./_content/AppJS/Components/Pages/JsCollocation3.razor.js");

複数のホスト型 Blazor アプリにコンポーネントと静的アセットを提供する

詳細については、「複数のホストされた ASP.NET Core Blazor WebAssembly アプリ」を参照してください。

クライアント側ブラウザー互換性アナライザー

クライアント側アプリは完全な .NET API アクセス領域を対象としていますが、ブラウザー サンドボックスの制約により、すべての .NET API が WebAssembly でサポートされているわけではありません。 サポートされていない API は、WebAssembly で実行すると PlatformNotSupportedException がスローされます。 開発者が、アプリのターゲット プラットフォームでサポートされていない API をアプリで使用すると、プラットフォーム互換性アナライザーから警告を受け取ります。 クライアント側アプリの場合、これは、API がブラウザーでサポートされているかどうかを確認すること意味します。 互換性アナライザーの .NET フレームワーク API に注釈を付けることは、進行中のプロセスであるため、現在、すべての .NET フレームワーク API に注釈が付けられるわけではありません。

対話型の WebAssembly コンポーネント、Blazor WebAssembly アプリ、RCL プロジェクトを有効にする Blazor Web App では、SupportedPlatform MSBuild 項目でサポートされているプラットフォームとして browser を追加することで、ブラウザーの互換性チェックが自動的に有効になります。 ライブラリ開発者は、SupportedPlatform 項目をライブラリのプロジェクト ファイルに手動で追加して、この機能を有効にすることができます。

<ItemGroup>
  <SupportedPlatform Include="browser" />
</ItemGroup>

ライブラリを作成する場合は、UnsupportedOSPlatformAttributebrowser を指定して、ブラウザーで特定の API がサポートされていないことを示します。

using System.Runtime.Versioning;

...

[UnsupportedOSPlatform("browser")]
private static string GetLoggingDirectory()
{
    ...
}

詳しくは、「特定のプラットフォームでサポートされていない API に注釈を付ける (dotnet/designs GitHub リポジトリ)」を参照してください。

JavaScript モジュールでの JavaScript の分離

Blazor により、標準 JavaScript モジュールで JavaScript の分離が有効にされます。 JavaScript の分離には、次のような利点があります。

  • インポートされる JavaScript によって、グローバル名前空間が汚染されなくなります。
  • ライブラリおよびコンポーネントのコンシューマーは、関連する JavaScript を手動でインポートする必要がありません。

詳しくは、「ASP.NET Core Blazor で .NET メソッドから JavaScript 関数を呼び出す」をご覧ください。

JavaScript で呼び出し可能な .NET メソッドのトリミングを回避する

ランタイムの再リンクの場合、JavaScript で呼び出し可能なクラス インスタンス .NET メソッドは、明示的に保持されていない限り、トリミングされます。 詳細については、「ASP.NET Core Blazor で JavaScript 関数から .NET メソッドを呼び出す」を参照してください。

ビルド、パック、NuGet への配布

Razor コンポーネントを含む Razor クラス ライブラリは標準 .NET ライブラリであるため、それらをパッキングして NuGet に配布することは、任意のライブラリをパッキングして NuGet に配布する場合と変わりはありません。 パッキングは、コマンド シェルで dotnet pack コマンドを使用して実行します。

dotnet pack

コマンド シェルで dotnet nuget push コマンドを使用して、パッケージを NuGet にアップロードします。

商標

Jeep および Jeep YJ は、FCA US LLC (Stellantis NV) の登録商標です。

その他の技術情報