注記
これは、この記事の最新バージョンではありません。 現在のリリースについては、 この記事の .NET 9 バージョンを参照してください。
警告
このバージョンの ASP.NET Core はサポート対象から除外されました。 詳細については、 .NET および .NET Core サポート ポリシーを参照してください。 現在のリリースについては、 この記事の .NET 9 バージョンを参照してください。
重要
この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。
現在のリリースについては、 この記事の .NET 9 バージョンを参照してください。
この記事では、Blazor アプリから Web API を呼び出す方法について説明します。
パッケージ
System.Net.Http.Json
パッケージには、System.Net.Http.HttpClient を使用した自動シリアル化と逆シリアル化を実行する System.Net.Http.HttpContent と System.Text.Json
の拡張メソッドが用意されています。
System.Net.Http.Json
パッケージは .NET 共有フレームワークによって提供され、アプリへのパッケージ参照を追加する必要はありません。
Web API 呼び出しにトークン ハンドラーを使用する
Blazor Web AppOIDC 認証では、トークン ハンドラーアプローチを使用して、外部 Web API 呼び出しをセキュリティで保護するための送信要求を行うことができます。 この方法は、この記事の「サンプル アプリ」セクションで説明されているBlazorWebAppOidc
およびBlazorWebAppOidcServer
サンプル アプリによって使用されます。
詳細については、次のリソースを参照してください。
- ASP.NET Core のサーバーサイドとBlazor Web App追加のセキュリティ シナリオ
- OpenID Connect (OIDC) を使用して ASP.NET Core Blazor Web App をセキュリティで保護する
Web API 呼び出し用の Microsoft ID プラットフォーム
Blazor Web AppMicrosoft アイデンティティ プラットフォームと Microsoft Entra ID 用の Microsoft Identity Web パッケージを使用するアプリケーションは、によって提供される API を使用して、合理化された Web API 呼び出しを行うことができます。
注記
.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ消費ワークフローでの パッケージのインストールと管理(NuGet ドキュメント)」の記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。
アプリ設定ファイル (appsettings.json
) で、ベース URL とスコープを指定します。 次の例では、 {BASE ADDRESS}
プレースホルダーは Web API のベース URL です。 単一のスコープは、アプリ ID URI ({APP ID URI}
プレースホルダー) とスコープ名 ({SCOPE NAME}
プレースホルダー) で指定されます。
"DownstreamApi": {
"BaseUrl": "{BASE ADDRESS}",
"Scopes": [ "{APP ID URI}/{SCOPE NAME}" ]
}
例:
"DownstreamApi": {
"BaseUrl": "https://localhost:7277",
"Scopes": [ "api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get" ]
}
アプリの Program
ファイルで、次を呼び出します。
- EnableTokenAcquisitionToCallDownstreamApi: トークン取得を有効にして Web API を呼び出します。
-
AddDownstreamApi
: Microsoft Identity Web パッケージは、Web API 呼び出しを行う名前付きダウンストリーム Web サービスを作成するための API を提供します。 IDownstreamApiは、外部 Web API (CallApiForUserAsync プロジェクト) から気象データを取得するためにMinimalApiJwt
を呼び出すために使用されるサーバー側クラスに挿入されます。 - AddDistributedTokenCaches: .NET Core 分散トークン キャッシュをサービス コレクションに追加します。
- AddDistributedMemoryCache: キャッシュ項目をメモリに格納する IDistributedCache の既定の実装を追加します。
- 分散トークン キャッシュ オプション (MsalDistributedTokenCacheAdapterOptions) を構成します。
- デバッグを目的とした開発では、 DisableL1Cache を
true
に設定することで、L1 キャッシュを無効にすることができます。 運用環境では、必ずfalse
にリセットしてください。 -
L1CacheOptions.SizeLimit
を使用して L1 キャッシュの最大サイズを設定して、キャッシュがサーバーのメモリをオーバーランしないようにします。 既定値は 500 MB です。 - デバッグ目的での開発では、 Encrypt を
false
(既定値) に設定することで、保存時のトークン暗号化を無効にすることができます。 運用環境では、必ずtrue
にリセットしてください。 - SlidingExpirationを使用してキャッシュからトークンの削除を設定します。 既定値は 1 時間です。
- L2 キャッシュ エラー (OnL2CacheFailure) のコールバックと非同期の L2 キャッシュ書き込み (EnableAsyncL2Write) に関するガイダンスなど、詳細については、「 MsalDistributedTokenCacheAdapterOptions と トークン キャッシュのシリアル化: 分散トークン キャッシュ」を参照してください。
- デバッグを目的とした開発では、 DisableL1Cache を
キャッシュを暗号化することを選択できます。運用環境では常に暗号化する必要があります。
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddDownstreamApi("DownstreamApi",
builder.Configuration.GetSection("DownstreamApi"))
.AddDistributedTokenCaches();
// Requires the 'Microsoft.Extensions.Caching.Memory' NuGet package
builder.Services.AddDistributedMemoryCache();
builder.Services.Configure<MsalDistributedTokenCacheAdapterOptions>(
options =>
{
// The following lines that are commented out reflect
// default values. We recommend overriding the default
// value of Encrypt to encrypt tokens at rest.
//options.DisableL1Cache = false;
//options.L1CacheOptions.SizeLimit = 500 * 1024 * 1024;
options.Encrypt = true;
//options.SlidingExpiration = TimeSpan.FromHours(1);
});
メモリ内分散トークン キャッシュは、 AddDistributedTokenCaches を呼び出すときに作成され、分散トークン キャッシュに使用できる基本実装があることを確認します。
運用 Web アプリと Web API では、運用分散トークン キャッシュ ( Redis、 Microsoft SQL Server、 Microsoft Azure Cosmos DB など) を使用する必要があります。
注記
1 台のコンピューターでのローカル開発とテストでは、分散トークン キャッシュの代わりにメモリ内トークン キャッシュを使用できます。
builder.Services.AddInMemoryTokenCaches();
開発とテストの期間の後半で、運用分散トークン キャッシュ プロバイダーを採用します。
AddDistributedMemoryCache は、キャッシュ項目をメモリに格納する IDistributedCache の既定の実装を追加します。これは、トークン キャッシュのために Microsoft Identity Web によって使用されます。
AddDistributedMemoryCache には、 Microsoft.Extensions.Caching.Memory
NuGet パッケージへのパッケージ参照が必要です。
注記
.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ消費ワークフローでの パッケージのインストールと管理(NuGet ドキュメント)」の記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。
運用分散キャッシュ プロバイダーを構成するには、 ASP.NET Core での分散キャッシュに関するページを参照してください。
警告
運用環境にアプリをデプロイするときは、常にメモリ内分散トークン キャッシュを実際のトークン キャッシュ プロバイダーに置き換えます。 運用分散トークン キャッシュ プロバイダーを採用できない場合、アプリのパフォーマンスが大幅に低下する可能性があります。
詳細については、「 トークン キャッシュのシリアル化: 分散キャッシュ」を参照してください。 ただし、示されているコード例は、AddDistributedMemoryCacheではなく、AddDistributedTokenCache経由で分散キャッシュを構成する ASP.NET Core アプリには適用されません。
運用環境で共有 Data Protection キー リングを使用すると、Web ファーム内のサーバー間でアプリのインスタンスが、 MsalDistributedTokenCacheAdapterOptions.Encrypt が true
に設定されているときにトークンを復号化できます。
注記
1 台のコンピューターでの早期開発とローカル テストでは、 Encrypt を false
に設定し、後で共有 Data Protection キー リングを構成できます。
options.Encrypt = false;
開発とテストの期間の後半で、トークン暗号化を有効にし、共有データ保護キー リングを採用します。
次の例は、共有キー リングに Azure Blob Storage と Azure Key Vault (PersistKeysToAzureBlobStorage
/ProtectKeysWithAzureKeyVault
) を使用する方法を示しています。 サービス構成は、デモンストレーションを目的としたベース ケース シナリオです。 運用アプリをデプロイする前に、Azure サービスを理解し、このセクションの最後に記載されている専用のドキュメント セットを使用してベスト プラクティスを採用してください。
Blazor Web Appのサーバー プロジェクトに次のパッケージを追加します。
注記
.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ消費ワークフローでの パッケージのインストールと管理(NuGet ドキュメント)」の記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。
注記
次の手順に進む前に、アプリが Microsoft Entra に登録されていることを確認します。
データ保護キーを維持し、Azure Key Vault を使用して保存時に暗号化するように Azure Blob Storage を構成します。
Azure ストレージ アカウントを作成します。 次の例のアカウント名は
contoso
。データ保護キーを保持するコンテナーを作成します。 次の例のコンテナー名は
data-protection
です。ローカル コンピューターにキー ファイルを作成します。 次の例では、キー ファイルの名前は
keys.xml
です。 テキスト エディターを使用してファイルを作成できます。keys.xml
:<?xml version="1.0" encoding="utf-8"?> <repository> </repository>
キー ファイル (
keys.xml
) をストレージ アカウントのコンテナーにアップロードします。 ポータルのキー行の末尾にあるコンテキスト メニューの [表示/編集] コマンドを使用して、BLOB に上記のコンテンツが含まれていることを確認します。コンテキスト メニューの [SAS の生成 ] コマンドを使用して、SHARED Access Signature (SAS) を使用して BLOB の URI を取得します。 SAS を作成するときは、
Read
、Add
、Create
、Write
、Delete
のアクセス許可を使用します。 URI は、後で{BLOB URI WITH SAS}
プレースホルダーが表示される場所で使用されます。
Entra または Azure portal でキー ボルトを確立する場合:
ボールトアクセス ポリシーを使用するようにキー ボールトを構成します。 [ネットワーク] ステップでパブリック アクセスが有効になっていることを確認します (オン)。
[ アクセス ポリシー ] ウィンドウで、
Get
、Unwrap Key
、およびWrap Key
キーのアクセス許可を持つ新しいアクセス ポリシーを作成します。 登録されているアプリケーションをサービス プリンシパルとして選択します。キー暗号化がアクティブな場合、キー ファイル内のキーにコメント "This key is encrypted with Azure Key Vault." が含まれる場合は、アプリを起動した後、キー行の末尾にあるコンテキスト メニューから [表示/編集] コマンドを選択して、キー コンテナーのセキュリティが適用されていることを確認します。
次の例の AzureEventSourceLogForwarder サービスは、ログ記録のために Azure SDK からログ メッセージを転送し、 Microsoft.Extensions.Azure
NuGet パッケージを必要とします。
注記
.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ消費ワークフローでの パッケージのインストールと管理(NuGet ドキュメント)」の記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。
Program
ファイルの先頭で、Microsoft.Extensions.Azure名前空間の API へのアクセスを指定します。
using Microsoft.Extensions.Azure;
サービスが登録されている Program
ファイルで、次のコードを使用します。
builder.Services.TryAddSingleton<AzureEventSourceLogForwarder>();
builder.Services.AddDataProtection()
.PersistKeysToAzureBlobStorage(new Uri("{BLOB URI WITH SAS}"))
.ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), new DefaultAzureCredential());
{BLOB URI WITH SAS}
: クエリ文字列パラメーターとして SAS トークンを使用してキー ファイルを格納する必要がある完全な URI。 URI は、アップロードされたキー ファイルの SAS を要求すると、Azure Storage によって生成されます。 次の例のコンテナー名は data-protection
で、ストレージ アカウント名は contoso
。 キー ファイルの名前は keys.xml
です。
例:
https://contoso.blob.core.windows.net/data-protection/keys.xml?sp={PERMISSIONS}&st={START DATETIME}&se={EXPIRATION DATETIME}&spr=https&sv={STORAGE VERSION DATE}&sr=c&sig={TOKEN}
{KEY IDENTIFIER}
: キー暗号化に使用される Azure Key Vault キー識別子。 次の例では、キー コンテナー名が contoso
され、アクセス ポリシーにより、アプリケーションは Get
、 Unwrap Key
、および Wrap Key
のアクセス許可を持つキー コンテナーにアクセスできます。 キー名の例は data-protection
。 キーのバージョン ({KEY VERSION}
プレースホルダー) は、作成後に Entra または Azure portal のキーから取得されます。
例:
https://contoso.vault.azure.net/keys/data-protection/{KEY VERSION}
ユーザーの代わりに呼び出すときに IDownstreamApi を挿入し、 CallApiForUserAsync を呼び出します。
internal sealed class ServerWeatherForecaster(IDownstreamApi downstreamApi) : IWeatherForecaster
{
public async Task<IEnumerable<WeatherForecast>> GetWeatherForecastAsync()
{
var response = await downstreamApi.CallApiForUserAsync("DownstreamApi",
options =>
{
options.RelativePath = "/weather-forecast";
});
return await response.Content.ReadFromJsonAsync<WeatherForecast[]>() ??
throw new IOException("No weather forecast!");
}
}
この方法は、この記事の「サンプル アプリ」セクションで説明されているBlazorWebAppEntra
およびBlazorWebAppEntraBff
サンプル アプリによって使用されます。
詳細については、次のリソースを参照してください。
- Web API ドキュメント |Microsoft ID プラットフォーム
- Web API を呼び出す Web API: API を呼び出す: オプション 2: ヘルパー クラスを使用してダウンストリーム Web API を呼び出す
- IDownstreamApi
- Microsoft Entra ID を使用して ASP.NET Core Blazor Web App をセキュリティで保護する
- Web ファームで ASP.NET Core をホストする: データ保護
- ASP.NET Core データ保護を構成する
- ASP.NET Core でのキー ストレージ プロバイダー
- Azure Key Vault のドキュメント
- Azure Storage のドキュメント
サンプル アプリ
実際の例については、 Blazor サンプル GitHub リポジトリ (dotnet/blazor-samples
) の次のサンプル アプリ (ダウンロード方法) を参照してください。
BlazorWebAppCallWebApi
Blazor Web App から外部の (Blazor Web App にはない) ToDo リスト Web API を呼び出します。
-
Backend
: 最小限の API に基づいて todo リストを維持するための Web API アプリ。 Web API アプリは、Blazor Web App とは別のアプリであり、別のサーバーでホストされている可能性があります。 -
BlazorApp
/BlazorApp.Client
: ToDo リストからのアイテムの作成、読み取り、更新、削除 (CRUD) などの ToDo リスト操作をBlazor Web App を使用して Web API アプリを呼び出す HttpClient。
CSR を採用した対話型 WebAssembly コンポーネントと Auto コンポーネントを含むクライアント側レンダリング (CSR) の場合、クライアント プロジェクト (HttpClient) の Program
ファイルに登録された構成済みの BlazorApp.Client
を使用して呼び出しが行われます。
builder.Services.AddScoped(sp =>
new HttpClient
{
BaseAddress = new Uri(builder.Configuration["FrontendUrl"] ??
"https://localhost:5002")
});
事前レンダリングされた対話型のサーバー コンポーネント、プリレンダリングされた WebAssembly コンポーネント、プリレンダリングされた、または SSR を採用した Auto コンポーネントを含む、サーバー側レンダリング (SSR) の場合、呼び出しは、サーバー プロジェクト (HttpClient) の Program
ファイルに登録された BlazorApp
で行われます。
builder.Services.AddHttpClient();
内部 (Blazor Web App 内) のムービー リスト API を呼び出します。この API は、Blazor Web App のサーバー プロジェクトに存在します。
-
BlazorApp
: ムービー リストを保持する Blazor Web App。- サーバー上のアプリ内でムービー リストに対して操作が実行されると、通常の API 呼び出しが使用されます。
- Web ベースのクライアントによって API 呼び出しが行われる場合、最小限の API に基づいて、ムービー リストの操作に Web API が使用されます。
-
BlazorApp.Client
: Blazor Web App のクライアント プロジェクト。ムービー リストのユーザー管理用の対話型 WebAssembly コンポーネントと自動コンポーネントが含まれています。
CSR を採用した対話型 WebAssembly コンポーネントと Auto コンポーネントを含む CSR の場合、API の呼び出しは、クライアント プロジェクト (ClientMovieService
) の HttpClient ファイルに登録された構成済みの Program
を使用するクライアントベースのサービス (BlazorApp.Client
) 経由で行われます。 これらの呼び出しはパブリック Web またはプライベート Web 経由で行われるため、ムービー リスト API は Web API です。
次の例では、/movies
エンドポイントからムービー リストを取得します。
public class ClientMovieService(HttpClient http) : IMovieService
{
public async Task<Movie[]> GetMoviesAsync(bool watchedMovies) =>
await http.GetFromJsonAsync<Movie[]>("movies") ?? [];
}
事前レンダリングされた対話型のサーバー コンポーネント、プリレンダリングされた WebAssembly コンポーネント、プリレンダリングされた、または SSR を採用した Auto コンポーネントを含む、SSR の場合、呼び出しは、サーバーベースのサービス (ServerMovieService
) 経由で直接行われます。 API はネットワークに依存しないため、これはムービー リスト CRUD 操作用の標準 API です。
次の例では、映画の一覧を取得します。
public class ServerMovieService(MovieContext db) : IMovieService
{
public async Task<Movie[]> GetMoviesAsync(bool watchedMovies) =>
watchedMovies ?
await db.Movies.Where(t => t.IsWatched).ToArrayAsync() :
await db.Movies.ToArrayAsync();
}
このシナリオで映画データをセキュリティで保護する方法の詳細については、 インタラクティブ自動レンダリングを使用して Blazor Web Appのデータをセキュリティで保護する方法で説明されている気象データの例を参照してください。
BlazorWebAppCallWebApi_Weather
気象データにストリーミング レンダリングを使用する気象データ サンプル アプリ。
BlazorWebAssemblyCallWebApi
Blazor WebAssembly アプリから ToDo リスト Web API を呼び出します。
-
Backend
: 最小限の API に基づいて todo リストを維持するための Web API アプリ。 -
BlazorTodo
: 構成済みのBlazor WebAssemblyを使用してToDoリストのCRUD操作を行うWeb APIを呼び出すHttpClientアプリ。
BlazorWebAssemblyStandaloneWithIdentity
ASP.NET Core Blazor WebAssemblyでセキュリティ保護されたスタンドアロン Identity アプリ:
-
Backend
: ASP.NET Core Identityのユーザー ID ストアを保持するバックエンド Web API アプリ。 -
BlazorWasmAuth
: ユーザー認証を使用するスタンドアロン Blazor WebAssembly フロントエンド アプリ。
このソリューションでは、次のセキュリティで保護された Web API の呼び出しを示します。
BlazorWebAppOidc
Entra 固有のパッケージを使用せずに Microsoft Entra で OIDC 認証を使用するグローバル自動対話機能を備えた Blazor Web App。 このサンプルでは、 Web API 呼び出しにトークン ハンドラーを使用 して、外部のセキュリティで保護された Web API を呼び出す方法を示します。
BlazorWebAppOidcServer
Microsoft Entra で OIDC 認証を使用し、Entra 特有のパッケージを使用せずに、グローバルなインタラクティブサーバーの操作性を備えた Blazor Web App。 このサンプルでは、 アクセス トークンを渡 して外部のセキュリティで保護された Web API を呼び出す方法を示します。
BlazorWebAppOidcBff
以下を使用するグローバル自動対話機能を備えた Blazor Web App:
- Entra 固有のパッケージを使用しない Microsoft Entra での OIDC 認証。
- フロントエンド用バックエンド (BFF) パターン。これは、フロントエンド アプリまたはインターフェイス用のバックエンド サービスを作成するアプリ開発のパターンです。
このソリューションには、対話型自動レンダリングを採用するコンポーネントがクライアントにレンダリングされるときに、外部 Web API を介して気象データを安全に取得するデモが含まれています。
BlazorWebAppEntra
Blazor Web App は、Microsoft Entra ID 用に IdentityとMicrosoft Web パッケージを利用するグローバルな自動対話機能を備えています。 このソリューションには、対話型自動レンダリングを採用するコンポーネントがクライアントにレンダリングされるときに、外部 Web API を介して気象データを安全に取得するデモが含まれています。
BlazorWebAppEntraBff
以下を使用するグローバル自動対話機能を備えた Blazor Web App:
- Microsoft Entra ID 用の Microsoft Identity Web パッケージを使用した Microsoft ID プラットフォーム。
- フロントエンド用バックエンド (BFF) パターン。これは、フロントエンド アプリまたはインターフェイス用のバックエンド サービスを作成するアプリ開発のパターンです。
このソリューションには、対話型自動レンダリングを採用するコンポーネントがクライアントにレンダリングされるときに、外部 Web API を介して気象データを安全に取得するデモが含まれています。
HttpRequestMessage
、HttpResponseMessage
、およびHttpClient
の処分
本文のない HttpRequestMessage では、 using
宣言 (C# 8 以降) または using
ブロック (すべての C# リリース) を使用して明示的に破棄する必要はありませんが、次の理由から、すべての用途で破棄することをお勧めします。
- ファイナライザーを回避してパフォーマンスを向上させる。
- 将来的に、最初から要求本文が含まれていないHttpRequestMessageに要求本文が追加される可能性に備えて、コードを堅牢化します。
- 委任ハンドラーが Dispose/DisposeAsyncの呼び出しを想定している場合に、機能上の問題を回避する可能性があります。
- 特定のケースを覚えるよりも、あらゆる場所に一般的なルールを適用する方が簡単です。
常にHttpResponseMessageインスタンスを破棄します。
を呼び出して作成されたインスタンスはフレームワークによって管理されるため、破棄HttpClient。
例:
using var request = new HttpRequestMessage(HttpMethod.Get, "/weather-forecast");
var client = clientFactory.CreateClient("ExternalApi");
using var response = await client.SendAsync(request);
外部 Web API を呼び出すためのクライアント側のシナリオ
クライアント ベースのコンポーネントは、HttpClient インスタンスを使用して外部 Web API を呼び出します。通常は、HttpClient ファイルに登録された構成済みの Program
で作成されます。
builder.Services.AddScoped(sp =>
new HttpClient
{
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
});
次の Razor コンポーネントは、ASP.NET Core 記事の IHttpClientFactory を使用した HTTP 要求の作成に関する記事の基本的な使用方法の例と同様に、GitHub ブランチ用の Web API に対して要求を行います。
CallWebAPI.razor
:
@page "/call-web-api"
@using System.Text.Json
@using System.Text.Json.Serialization
@inject HttpClient Client
<h1>Call web API from a Blazor WebAssembly Razor component</h1>
@if (getBranchesError || branches is null)
{
<p>Unable to get branches from GitHub. Please try again later.</p>
}
else
{
<ul>
@foreach (var branch in branches)
{
<li>@branch.Name</li>
}
</ul>
}
@code {
private IEnumerable<GitHubBranch>? branches = [];
private bool getBranchesError;
private bool shouldRender;
protected override bool ShouldRender() => shouldRender;
protected override async Task OnInitializedAsync()
{
using var request = new HttpRequestMessage(HttpMethod.Get,
"https://api.github.com/repos/dotnet/AspNetCore.Docs/branches");
request.Headers.Add("Accept", "application/vnd.github.v3+json");
request.Headers.Add("User-Agent", "HttpClientFactory-Sample");
using var response = await Client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync();
branches = await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubBranch>>(responseStream);
}
else
{
getBranchesError = true;
}
shouldRender = true;
}
public class GitHubBranch
{
[JsonPropertyName("name")]
public string? Name { get; set; }
}
}
C# 12 以降の前の例では、[]
変数のために空の配列 (branches
) が作成されています。 .NET 8 より前の SDK でコンパイルされた以前のバージョンの C# では、空の配列 (Array.Empty<GitHubBranch>()
) を作成します。
.NET/C# コードとデータを保護するには、 ASP.NET Core Data Protection 機能をサーバー側の ASP.NET Core バックエンド Web API と共に使用します。 クライアント側の Blazor WebAssembly アプリは、セキュリティで保護されたアプリ機能とデータ処理のためにサーバー側 Web API を呼び出します。
Blazor WebAssembly アプリは多くの場合、 クロスオリジン要求共有 (CORS) セキュリティにより、配信元間で Web API への直接呼び出しを行うことができなくなります。 一般的な例外は次のようになります。
'{URL}' で オリジン 'https://localhost:{PORT}'' からのフェッチへのアクセスは CORS ポリシーによってブロックされました: 要求されたリソースに 'Access-Control-Allow-Origin' ヘッダーが存在しません。 不透明な応答がニーズに応える場合は、要求のモードを "no-cors" に設定して、CORS を無効にしてリソースをフェッチします。
上記の例外を回避しようとしている SetBrowserRequestMode (1) の BrowserRequestMode フィールドを使用して NoCors
を呼び出した場合でも、Web API の配信元に対する CORS 制限 (特定の配信元からの呼び出しのみを許可する制限や、ブラウザーからの JavaScript fetch
要求を妨げる制限など) によって要求が失敗することがよくあります。 このような呼び出しを成功させる唯一の方法は、呼び出している Web API が、正しい CORS 構成でのオリジンの呼び出しを許可することです。 ほとんどの外部 Web API では、CORS ポリシーを構成できません。 この制限に対処するには、次のいずれかの方法を採用します。
独自のサーバー側 ASP.NET Core バックエンド Web API を維持します。 クライアント側 Blazor WebAssembly アプリはサーバー側の Web API を呼び出し、Web API は(ブラウザーではなく) サーバーベースの C# コードから、正しい CORS ヘッダーを使用して外部 Web API に要求を行い、結果をクライアント側の Blazor WebAssembly アプリに返します。
プロキシ サービスを使用して、クライアント側の Blazor WebAssembly アプリから外部 Web API に要求をプロキシします。 プロキシ サービスは、サーバー側アプリを使用してクライアントに代わって要求を行い、呼び出しが成功した後に結果を返します。 CloudFlare の CORS PROXY 基づく次の例では、
{REQUEST URI}
プレースホルダーは要求 URI です。@using System.Net @inject IHttpClientFactory ClientFactory ... @code { public async Task CallApi() { var client = ClientFactory.CreateClient(); var urlEncodedRequestUri = WebUtility.UrlEncode("{REQUEST URI}"); using var request = new HttpRequestMessage(HttpMethod.Get, $"https://corsproxy.io/?{urlEncodedRequestUri}"); using var response = await client.SendAsync(request); ... } }
外部 Web API を呼び出すためのサーバー側のシナリオ
サーバーベースのコンポーネントからは HttpClient インスタンス (通常、IHttpClientFactory を使用して作成されます) を使用して外部 Web API を呼び出します。 サーバー側アプリに適用されるガイダンスについては、「 ASP.NET Core で IHttpClientFactory を使用して HTTP 要求を行う」を参照してください。
サーバー側アプリには、HttpClient サービスが含まれません。
HttpClient
HttpClient
を使用してアプリにを提供します。
Program
ファイルで次の操作を行います。
builder.Services.AddHttpClient();
次の Razor コンポーネントは、ASP.NET Core 記事の IHttpClientFactory を使用した HTTP 要求の作成に関する記事の基本的な使用方法の例と同様に、GitHub ブランチ用の Web API に対して要求を行います。
CallWebAPI.razor
:
@page "/call-web-api"
@using System.Text.Json
@using System.Text.Json.Serialization
@inject IHttpClientFactory ClientFactory
<h1>Call web API from a server-side Razor component</h1>
@if (getBranchesError || branches is null)
{
<p>Unable to get branches from GitHub. Please try again later.</p>
}
else
{
<ul>
@foreach (var branch in branches)
{
<li>@branch.Name</li>
}
</ul>
}
@code {
private IEnumerable<GitHubBranch>? branches = [];
private bool getBranchesError;
private bool shouldRender;
protected override bool ShouldRender() => shouldRender;
protected override async Task OnInitializedAsync()
{
using var request = new HttpRequestMessage(HttpMethod.Get,
"https://api.github.com/repos/dotnet/AspNetCore.Docs/branches");
request.Headers.Add("Accept", "application/vnd.github.v3+json");
request.Headers.Add("User-Agent", "HttpClientFactory-Sample");
var client = ClientFactory.CreateClient();
using var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync();
branches = await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubBranch>>(responseStream);
}
else
{
getBranchesError = true;
}
shouldRender = true;
}
public class GitHubBranch
{
[JsonPropertyName("name")]
public string? Name { get; set; }
}
}
C# 12 以降の前の例では、[]
変数のために空の配列 (branches
) が作成されています。 .NET 8 より前の SDK でコンパイルされた以前のバージョンの C# では、空の配列 (Array.Empty<GitHubBranch>()
) を作成します。
その他の作業例については、ASP.NET Core Blazor ファイルのアップロードに関する記事の Web API コントローラーにファイルをアップロードするサーバー側のファイルアップロードの例を参照してください。
Web API 呼び出しのサービス抽象化
このセクションは、サーバー プロジェクトで Web API を管理する Blazor Web App、または Web API 呼び出しを外部 Web API に変換する場合に適用されます。
対話型の WebAssembly および Auto レンダリング モードを使用する場合、コンポーネントは既定でプリレンダリングされます。 また、Blazor バンドルがクライアントにダウンロードされ、クライアント側ランタイムがアクティブ化される前に、Auto コンポーネントが最初にサーバーから対話形式でレンダリングされます。 つまり、これらのレンダリング モードを使用するコンポーネントは、クライアントとサーバーの両方から正常に実行されるように設計する必要があります。 コンポーネントでサーバー プロジェクト ベースの API を呼び出すか、クライアントでの実行時に外部 Web API (Blazor Web App の外部にあるもの) に要求を変換する必要がある場合は、サービス インターフェイスの背後でその API 呼び出しを抽象化し、サービスのクライアントとサーバーのバージョンを実装することをお勧めします。
- クライアント バージョンは、構成済みの HttpClient を使用して Web API を呼び出します。
- サーバー バージョンは通常、サーバー側のリソースに直接アクセスできます。 ネットワーク要求は通常不要であるため、サーバーへの呼び出しを行う HttpClient をサーバーに挿入することは推奨されません。 または、API がサーバー プロジェクトの外部にある可能性がありますが、プロキシされた要求にアクセス トークンを追加するなど、何らかの方法で要求を変換するにはサーバーのサービス抽象化が必要です。
WebAssembly レンダリング モードを使用する場合は、コンポーネントがクライアントからのみレンダリングされるように、プリレンダリングを無効にすることもできます。 詳細については、「 コア Blazor レンダリング モード ASP.NET」を参照してください。
例 (サンプル アプリ):
-
BlazorWebAppCallWebApi
サンプル アプリのムービー リスト Web API。 -
BlazorWebAppCallWebApi_Weather
サンプル アプリでの気象データ レンダリング Web API のストリーミング。 -
BlazorWebAppOidc
(BFF 以外のパターン) またはBlazorWebAppOidcBff
(BFF パターン) サンプル アプリのいずれかでクライアントに返される気象データ。 これらのアプリは、セキュリティで保護された (Web) API 呼び出しを示しています。 詳細については、「 OpenID Connect (OIDC) を使用して ASP.NET Core Blazor Web App をセキュリティで保護する」を参照してください。
Blazor Web App 外部 Web API
このセクションは、別の (外部) プロジェクトによって管理されている Web API を呼び出す Blazor Web Appに適用されます。別のサーバーでホストされている可能性があります。
Blazor Web App は通常、クライアント側の WebAssembly コンポーネントをプリレンダリングし、Auto コンポーネントは静的または対話型のサーバー側のレンダリング (SSR) 中にサーバー上にレンダリングします。
HttpClient サービスは、既定では Blazor Web App のメイン プロ ジェクトに登録されません。 「HttpClient サービスの追加」セクションの説明に従って、.Client
プロジェクトに登録されているHttpClient
サービスのみでアプリを実行すると、アプリを実行するとランタイム エラーが発生します。
InvalidOperationException: Cannot provide a value for property 'Http' on type '...{COMPONENT}'. (InvalidOperationException: {COMPONENT}' 型では 'Http' プロパティの値を指定できません。) There is no registered service of type 'System.Net.Http.HttpClient'. ('System.Net.Http.HttpClient' 型の登録済みサービスはありません。)
次 のいずれかの 方法を使用します。
HttpClient サービスをサーバー プロジェクトに追加して、SSR 中に HttpClient を使用できるようにします。 サーバー プロジェクトの
Program
ファイルで、次のサービス登録を使います。builder.Services.AddHttpClient();
HttpClient サービスは共有フレームワークによって提供されるため、アプリのプロジェクト ファイル内のパッケージ参照は必要ありません。
例:
BlazorWebAppCallWebApi
サンプル アプリの Todo list Web APIWeb API を呼び出す WebAssembly コンポーネントにプリレンダリングが必要ない場合は、ASP.NET Core Blazor レンダリング モードのガイダンスに従ってプリレンダリングを無効にします。 この方法を採用する場合は、サーバー側でコンポーネントがプリレンダリングされないため、HttpClient のメイン プロジェクトに Blazor Web App サービス を追加する必要はありません。
詳細については、「 プリレンダリング中にクライアント側サービスが解決されない」を参照してください。
プリレンダリングされるデータ
プリレンダリング時に、コンポーネントは 2 回レンダリングされます。最初は静的に、次に対話形式でレンダリングされます。 状態は、プリレンダリングされたコンポーネントから対話型コンポーネントに自動的に流れるわけではありません。 コンポーネントが非同期の初期化操作を実行し、初期化中に異なる状態に対して別のコンテンツ ("読み込み中..." 進行インジケーターなど) をレンダリングする場合、コンポーネントが 2 回レンダリングされるときにちらつきが発生することがあります。
これは、BlazorWebAppCallWebApi
アプリと BlazorWebAppCallWebApi_Weather
サンプル アプリが示す永続的なコンポーネント状態 API を使用して、プリレンダリングされた状態をフローさせることで対処できます。 コンポーネントが対話形式でレンダリングされる場合、同じ状態を使用して同じ方法でレンダリングできます。 ただし、この API は現在、拡張ナビゲーションでは機能しません。これは、ページへのリンクの拡張ナビゲーションを無効にする (data-enhanced-nav=false
) ことで回避できます。 詳細については、次のリソースを参照してください。
クライアント側のリクエストストリーミング
HTTP/2 プロトコルと HTTPS を使用する Chromium ベースのブラウザー (Google Chrome や Microsoft Edge など) の場合、クライアント側の Blazor は Streams API を使用して 要求ストリーミングを許可します。
要求ストリーミングを有効にするには、SetBrowserRequestStreamingEnabledで true
を HttpRequestMessage に設定します。
次のファイルアップロードの例では、
-
content
ファイルの HttpContentです。 -
/Filesave
は Web API エンドポイントです。 -
Http
は HttpClientです。
using var request = new HttpRequestMessage(HttpMethod.Post, "/Filesave");
request.SetBrowserRequestStreamingEnabled(true);
request.Content = content;
using var response = await Http.SendAsync(request);
ストリーミング要求:
- HTTPS プロトコルが必要であり、HTTP/1.x では機能しません。
- 本文は含めますが
Content-Length
ヘッダーは含めません。 クロスオリジン ストリーミング要求には、プレフライト要求を含む CORS が必要です。
InputFile コンポーネントを使用したファイルのアップロードの詳細については、「ASP.NET Core Blazor ファイルのアップロード」と「クライアント側レンダリング (CSR) を使用してサーバーにファイルをアップロードする」の例を参照してください。
HttpClient
サービスを追加する
このセクションのガイダンスは、クライアント側のシナリオに適用されます。
クライアント側コンポーネントは、事前に構成された HttpClient サービスを使用して Web API を呼び出します。このサービスは、元のサーバーに要求を行うことに重点を置いています。 他の Web API 用の追加の HttpClient サービス構成は、開発者コードで作成できます。 要求は、Blazor JSON ヘルパーを使用して、または HttpRequestMessage で構成されます。 要求には Fetch API オプション構成を含めることができます。
このセクションの構成例は、アプリ内の 1 つの HttpClient インスタンスに対して 1 つの Web API が呼び出される場合にのみ役立ちます。 アプリで複数の Web API を呼び出す必要がある場合は、それぞれ独自のベース アドレスと構成を使用します。その場合、この記事の後半で説明する方法を採用できます。
-
HttpClient
を使用した名前付きIHttpClientFactory
: 各 Web API には一意の名前が付けられます。 アプリ コードまたは Razor コンポーネントが Web API を呼び出すと、名前付き HttpClient インスタンスを使用して呼び出しが行われます。 -
型指定された
HttpClient
: 各 Web API は型指定されています。 アプリ コードまたは Razor コンポーネントが Web API を呼び出すと、型指定 HttpClient インスタンスを使用して呼び出しが行われます。
Program
ファイルで、アプリの作成に使用した HttpClient プロジェクト テンプレートから Blazor サービスを追加します (このサービスが存在していない場合)。
builder.Services.AddScoped(sp =>
new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
上記の例では、ベース アドレスの設定に builder.HostEnvironment.BaseAddress
(IWebAssemblyHostEnvironment.BaseAddress) を使っています。これを使って、アプリのベース アドレス (通常は、ホスト ページの <base>
タグの href
値に由来します) を取得できます。
クライアント独自のベース アドレスを使用する最も一般的なユース ケースは次のとおりです。
-
.Client
(.NET 8 以降) のクライアント プロジェクト (Blazor Web App) は、WebAssembly のクライアントで実行される WebAssembly コンポーネントまたはコードから、サーバー アプリの API への Web API 呼び出しを行います。 - ホストされている Client アプリのクライアント プロジェクト (Blazor WebAssembly) は、サーバー プロジェクト (Server) に対して Web API 呼び出しを行います。 Hosted Blazor WebAssembly プロジェクト テンプレートは、.NET 8 以降では使用できなくなりました。 ただし、ホストされている Blazor WebAssembly アプリは .NET 8 で引き続きサポートされます。
外部 Web API (クライアント アプリと同じ URL 空間にない) を呼び出す場合は、URI を Web API のベース アドレスに設定します。 次の例では、Web API のベース アドレスを https://localhost:5001
に設定します。これは、別の Web API アプリが実行される場所で、クライアント アプリからの要求に応答する準備ができています。
builder.Services.AddScoped(sp =>
new HttpClient { BaseAddress = new Uri("https://localhost:5001") });
JSON 補助機能
HttpClient は、元のサーバーに対して要求を行うための構成済みのサービスとして用意されています。
HttpClient と JSON のヘルパー (System.Net.Http.Json.HttpClientJsonExtensions) は、サード パーティの Web API エンドポイントを呼び出すためにも使用されます。 HttpClient はブラウザーの Fetch API を使用して実装され、同じ配信元ポリシーの適用など、その制限の対象となります。これについては、 クロスオリジン リソース共有 (CORS) セクションのこの記事で後述します。
クライアントのベース アドレスは、生成元のサーバーのアドレスに設定されます。
HttpClient ディレクティブを使用して @inject
インスタンスをコンポーネントに挿入します。
@using System.Net.Http
@inject HttpClient Http
System.Net.Http.Json にアクセスするには、HttpClientJsonExtensions 名前空間を使用します。これには、GetFromJsonAsync、PutAsJsonAsync、および PostAsJsonAsync が含まれます。
@using System.Net.Http.Json
次のセクションでは、JSON ヘルパーについて説明します。
System.Net.Http には、HTTP 要求を送信し、HTTP 応答を受信する (たとえば DELETE 要求を送信する) ための追加のメソッドが含まれています。 詳細については、「 DELETE と追加の拡張メソッド 」セクションを参照してください。
JSON から取得する (GetFromJsonAsync
)
GetFromJsonAsync は、HTTP GET 要求を送信し、JSON 応答本文を解析してオブジェクトを作成します。
次のコンポーネント コードでは、コンポーネントによって todoItems
が表示されます。
GetFromJsonAsync は、コンポーネントの初期化が完了すると呼び出されます (OnInitializedAsync
)。
todoItems = await Http.GetFromJsonAsync<TodoItem[]>("todoitems");
JSON として投稿する (PostAsJsonAsync
)
PostAsJsonAsync は、要求本文に JSON としてシリアル化された値が含まれる POST 要求を、指定された URI に送信します。
次のコンポーネント コードでは、コンポーネントのバインドされた要素によって newItemName
が提供されています。
AddItem
メソッドは、<button>
要素を選択することにでトリガーされます。
await Http.PostAsJsonAsync("todoitems", addItem);
PostAsJsonAsync では HttpResponseMessage が返されます。 応答メッセージから JSON コンテンツを逆シリアル化するには、ReadFromJsonAsync 拡張メソッドを使用します。 次の例では、JSON の気象データを配列として読み取ります。
var content = await response.Content.ReadFromJsonAsync<WeatherForecast[]>() ??
Array.Empty<WeatherForecast>();
JSON として配置する (PutAsJsonAsync
)
PutAsJsonAsync は、JSON でエンコードされたコンテンツを含む HTTP PUT 要求を送信します。
次のコンポーネント コードでは、editItem
および Name
の IsCompleted
値が、コンポーネントのバインドされた要素によって提供されています。 項目の Id
は、UI の別の部分 (表示されない) で項目が選択され、EditItem
が呼び出されたときに設定されます。
SaveItem
メソッドは、<button>
要素を選択することでトリガーされます。 次の例では、簡潔にするために todoItems
の読み込みを示していません。 項目の読み込みの例については、 JSON からの GET (GetFromJsonAsync
) セクションを参照してください。
await Http.PutAsJsonAsync($"todoitems/{editItem.Id}", editItem);
PutAsJsonAsync では HttpResponseMessage が返されます。 応答メッセージから JSON コンテンツを逆シリアル化するには、ReadFromJsonAsync 拡張メソッドを使用します。 次の例では、JSON の気象データを配列として読み取ります。
var content = await response.Content.ReadFromJsonAsync<WeatherForecast[]>() ??
Array.Empty<WeatherForecast>();
JSON 形式での PATCH (PatchAsJsonAsync
)
PatchAsJsonAsync では、JSON でエンコードされたコンテンツを含む HTTP PATCH 要求を送信します。
注記
詳細については、 ASP.NET Core Web API の JsonPatch に関するページを参照してください。
次の例で、PatchAsJsonAsync はエスケープされた引用符を含むプレーン テキスト文字列として JSON パッチ ドキュメントを受け取ります。
await Http.PatchAsJsonAsync(
$"todoitems/{id}",
"[{\"operationType\":2,\"path\":\"/IsComplete\",\"op\":\"replace\",\"value\":true}]");
C# 11 (.NET 7) の時点では、生の文字列リテラルとして JSON 文字列を作成できます。 コード分析ツールの StringSyntaxAttribute.Json[StringSyntax]
属性に対して、 フィールドを使用して JSON 構文を指定します。
@using System.Diagnostics.CodeAnalysis
...
@code {
[StringSyntax(StringSyntaxAttribute.Json)]
private const string patchOperation =
"""[{"operationType":2,"path":"/IsComplete","op":"replace","value":true}]""";
...
await Http.PatchAsJsonAsync($"todoitems/{id}", patchOperation);
}
PatchAsJsonAsync では HttpResponseMessage が返されます。 応答メッセージから JSON コンテンツを逆シリアル化するには、ReadFromJsonAsync 拡張メソッドを使用します。 次の例では、JSON の ToDo 項目データを配列として読み取ります。 メソッドによって項目データが返されない場合は空の配列が作成されるため、次のようにステートメントの実行後も content
は null 値にはなりません。
using var response = await Http.PatchAsJsonAsync(...);
var content = await response.Content.ReadFromJsonAsync<TodoItem[]>() ??
Array.Empty<TodoItem>();
インデント、スペース、エスケープされていない引用符を使用してレイアウトした、エンコードされていない PATCH ドキュメントは、次の JSON のようになります。
[
{
"operationType": 2,
"path": "/IsComplete",
"op": "replace",
"value": true
}
]
PATCH 要求を発行するアプリでの PATCH ドキュメントの作成を簡略化するため、次のガイダンスに示すように、アプリで .NET JSON PATCH サポートを使用することができます。
Microsoft.AspNetCore.JsonPatch.SystemTextJson
NuGet パッケージをインストールし、そのパッケージの API 機能を使用して、PATCH 要求における JsonPatchDocument
を作成します。
注記
.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ消費ワークフローでの パッケージのインストールと管理(NuGet ドキュメント)」の記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。
@using
コンポーネントの先頭に、System.Text.Json、System.Text.Json.Serialization、およびMicrosoft.AspNetCore.JsonPatch.SystemTextJson
名前空間のRazor ディレクティブを追加します。
@using System.Text.Json
@using System.Text.Json.Serialization
@using Microsoft.AspNetCore.JsonPatch.SystemTextJson
JsonPatchDocument
用の TodoItem
を作成するために、IsComplete
を true
に設定し、JsonPatchDocument.Replace
メソッドを使用します。
var patchDocument = new JsonPatchDocument<TodoItem>()
.Replace(p => p.IsComplete, true);
Microsoft.AspNetCore.JsonPatch
NuGet パッケージをインストールし、そのパッケージの API 機能を使用して、PATCH 要求における JsonPatchDocument を作成します。
注記
.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ消費ワークフローでの パッケージのインストールと管理(NuGet ドキュメント)」の記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。
@using
、System.Text.Json、System.Text.Json.Serialization 名前空間に対する Microsoft.AspNetCore.JsonPatch ディレクティブを、Razor コンポーネントの上部に追加します。
@using System.Text.Json
@using System.Text.Json.Serialization
@using Microsoft.AspNetCore.JsonPatch
JsonPatchDocument 用の TodoItem
を作成するために、IsComplete
を true
に設定し、Replace メソッドを使用します。
var patchDocument = new JsonPatchDocument<TodoItem>()
.Replace(p => p.IsComplete, true);
ドキュメントの操作 (patchDocument.Operations
) を PatchAsJsonAsync 呼び出しに渡します。
private async Task UpdateItem(long id)
{
await Http.PatchAsJsonAsync(
$"todoitems/{id}",
patchDocument.Operations,
new JsonSerializerOptions()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault
});
}
プロパティを、その型の既定値と等しい場合にのみ無視するように、JsonSerializerOptions.DefaultIgnoreCondition が JsonIgnoreCondition.WhenWritingDefault に設定されています。
JSON ペイロードを見やすい形式で表示するには、JsonSerializerOptions.WriteIndented を true
に設定して追加します。 インデントされた JSON の作成は、PATCH 要求の処理とは関係がなく、運用アプリにおける Web API 要求では通常実行されません。
ASP.NET Core Web API の JsonPatch に関する記事のガイダンスに従って、PATCH コントローラー アクションを Web API に追加します。 または、PATCH 要求処理は、次の手順で 最小限の API として実装できます。
Microsoft.AspNetCore.JsonPatch.SystemTextJson
NuGet パッケージのパッケージ参照を Web API アプリに追加します。
Program
ファイルで、@using
Microsoft.AspNetCore.JsonPatch.SystemTextJson
名前空間の ディレクティブを追加します。
using Microsoft.AspNetCore.JsonPatch.SystemTextJson;
Microsoft.AspNetCore.Mvc.NewtonsoftJson
NuGet パッケージのパッケージ参照を Web API アプリに追加します。
注記
Microsoft.AspNetCore.JsonPatch
パッケージへの参照によって自動的に Microsoft.AspNetCore.Mvc.NewtonsoftJson
のパッケージ参照が推移的に追加されるため、Microsoft.AspNetCore.JsonPatch
パッケージのパッケージ参照をアプリに追加する必要はありません。
Program
ファイルに、@using
名前空間の Microsoft.AspNetCore.JsonPatch ディレクティブを追加します。
using Microsoft.AspNetCore.JsonPatch;
Web API の要求処理パイプラインへのエンドポイントを指定します。
app.MapPatch("/todoitems/{id}", async (long id, TodoContext db) =>
{
if (await db.TodoItems.FindAsync(id) is TodoItem todo)
{
var patchDocument =
new JsonPatchDocument<TodoItem>().Replace(p => p.IsComplete, true);
patchDocument.ApplyTo(todo);
await db.SaveChangesAsync();
return TypedResults.Ok(todo);
}
return TypedResults.NoContent();
});
警告
ASP.NET Core Web API の記事の JsonPatch の他の例と同様に、上記の PATCH API では、Web API が過剰に投稿される攻撃から保護されません。 詳細については、「 チュートリアル: ASP.NET Core を使用してコントローラー ベースの Web API を作成する」を参照してください。
完全に動作する PATCH エクスペリエンスについては、 BlazorWebAppCallWebApi
サンプル アプリを参照してください。
DELETE (DeleteAsync
) およびその他の拡張メソッド
System.Net.Http には、HTTP 要求を送信し、HTTP 応答を受信するための追加の拡張メソッドが含まれています。 HttpClient.DeleteAsync は、HTTP DELETE 要求を Web API に送信するために使用します。
次のコンポーネント コードでは、<button>
要素で DeleteItem
メソッドを呼び出しています。 バインドされた <input>
要素では、削除する項目の id
が提供されます。
await Http.DeleteAsync($"todoitems/{id}");
HttpClient
による名前付き IHttpClientFactory
IHttpClientFactory サービスおよび名前付き HttpClient の構成がサポートされています。
注記
HttpClient からの名前付き IHttpClientFactory を使用する代替手段は、型指定された HttpClient を使うことです。 詳細については、「TypedHttpClient
」セクションを参照してください。
アプリに Microsoft.Extensions.Http
NuGet パッケージを追加します。
注記
.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ消費ワークフローでの パッケージのインストールと管理(NuGet ドキュメント)」の記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。
クライアント プロジェクトの Program
ファイルで、次のとおりです。
builder.Services.AddHttpClient("WebAPI", client =>
client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));
Blazor Web App のプリレンダリングされたクライアント側コンポーネントで名前付きクライアントを使用する場合は、サーバー プロジェクトと .Client
プロジェクトの両方に、上記のサービス登録が表示されます。 サーバーでは、builder.HostEnvironment.BaseAddress
が Web API のベース アドレスで置き換えられます。これは、以下で詳しく説明します。
上記のクライアント側の例では、ベース アドレスの設定に builder.HostEnvironment.BaseAddress
(IWebAssemblyHostEnvironment.BaseAddress) を使っています。これを使って、クライアント側アプリのベース アドレス (通常は、ホスト ページの <base>
タグの href
値に由来します) を取得できます。
クライアント独自のベース アドレスを使用する最も一般的なユース ケースは次のとおりです。
- WebAssemblyやAutoコンポーネントから、またはWebAssemblyでクライアント上で実行されるコードから、同一ホストアドレスのサーバーアプリのAPIに対してWeb API呼び出しを行う
.Client
のクライアントプロジェクト(Blazor Web App)。 - サーバー プロジェクト (Client) に対して Web API 呼び出しを行う、ホストされている Blazor WebAssembly アプリのクライアント プロジェクト (Server)。
クライアント独自のベース アドレスを使用する最も一般的なユース ケースは、サーバー プロジェクト (Client) に対して Web API 呼び出しを行う、ホストされている Blazor WebAssembly アプリのクライアント プロジェクト (Server) にあります。
(クライアント アプリと同じ URL 空間ではなく) 外部 Web API を呼び出す場合、またはサーバー側アプリでサービスを構成している場合 (たとえば、サーバー上のクライアント側コンポーネントのプリレンダリングを処理する場合)、URI を Web API のベース アドレスに設定します。 次の例では、Web API のベース アドレスを https://localhost:5001
に設定します。これは、別の Web API アプリが実行される場所で、クライアント アプリからの要求に応答する準備ができています。
builder.Services.AddHttpClient("WebAPI", client =>
client.BaseAddress = new Uri("https://localhost:5001"));
次のようなコンポーネント コードがあるとします。
- IHttpClientFactory のインスタンスによって、名前付きの HttpClient が作成されます。
- 名前付き HttpClient を使用して、
/forecast
の Web API から JSON の気象予報データの GET 要求が発行されます。
@inject IHttpClientFactory ClientFactory
...
@code {
private Forecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
var client = ClientFactory.CreateClient("WebAPI");
forecasts = await client.GetFromJsonAsync<Forecast[]>("forecast") ?? [];
}
}
BlazorWebAppCallWebApi
サンプル アプリは、HttpClient コンポーネントで名前付きCallTodoWebApiCsrNamedClient
を使用して Web API を呼び出す方法を示しています。 名前付きHttpClientを使用した Microsoft Graph の呼び出しに基づくクライアント アプリでの追加の動作デモンストレーションについては、「ASP.NET Core Blazor WebAssemblyでの Graph API の使用」を参照してください。
名前付きHttpClientを使用した Microsoft Graph の呼び出しに基づくクライアント アプリでの動作デモについては、「ASP.NET Core Blazor WebAssemblyでの Graph API の使用」を参照してください。
型指定された HttpClient
型指定された HttpClient では、1 つ以上のアプリの HttpClient インスタンス (既定または名前付き) を使用して、1 つ以上の Web API エンドポイントからデータを返します。
注記
型指定された HttpClient を使用する代替手段は、HttpClient からの名前付き IHttpClientFactory を使うことです。 詳細については、「 名前付き HttpClient
と IHttpClientFactory
」セクションを参照してください。
アプリに Microsoft.Extensions.Http
NuGet パッケージを追加します。
注記
.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ消費ワークフローでの パッケージのインストールと管理(NuGet ドキュメント)」の記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。
次の例では、/forecast
の Web API から JSON の気象予報データの GET 要求を発行します。
ForecastHttpClient.cs
:
using System.Net.Http.Json;
namespace BlazorSample.Client;
public class ForecastHttpClient(HttpClient http)
{
public async Task<Forecast[]> GetForecastAsync() =>
await http.GetFromJsonAsync<Forecast[]>("forecast") ?? [];
}
クライアント プロジェクトの Program
ファイルで、次のとおりです。
builder.Services.AddHttpClient<ForecastHttpClient>(client =>
client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));
Blazor Web App のプリレンダリングされたクライアント側コンポーネントで型指定されたクライアントを使用する場合は、サーバー プロジェクトと .Client
プロジェクトの両方に、上記のサービス登録が表示されます。 サーバーでは、builder.HostEnvironment.BaseAddress
が Web API のベース アドレスで置き換えられます。これは、以下で詳しく説明します。
上記の例では、ベース アドレスの設定に builder.HostEnvironment.BaseAddress
(IWebAssemblyHostEnvironment.BaseAddress) を使っています。これを使って、クライアント側アプリのベース アドレス (通常は、ホスト ページの <base>
タグの href
値に由来します) を取得できます。
クライアント独自のベース アドレスを使用する最も一般的なユース ケースは次のとおりです。
- WebAssemblyやAutoコンポーネントから、またはWebAssemblyでクライアント上で実行されるコードから、同一ホストアドレスのサーバーアプリのAPIに対してWeb API呼び出しを行う
.Client
のクライアントプロジェクト(Blazor Web App)。 - サーバー プロジェクト (Client) に対して Web API 呼び出しを行う、ホストされている Blazor WebAssembly アプリのクライアント プロジェクト (Server)。
クライアント独自のベース アドレスを使用する最も一般的なユース ケースは、サーバー プロジェクト (Client) に対して Web API 呼び出しを行う、ホストされている Blazor WebAssembly アプリのクライアント プロジェクト (Server) にあります。
(クライアント アプリと同じ URL 空間ではなく) 外部 Web API を呼び出す場合、またはサーバー側アプリでサービスを構成している場合 (たとえば、サーバー上のクライアント側コンポーネントのプリレンダリングを処理する場合)、URI を Web API のベース アドレスに設定します。 次の例では、Web API のベース アドレスを https://localhost:5001
に設定します。これは、別の Web API アプリが実行される場所で、クライアント アプリからの要求に応答する準備ができています。
builder.Services.AddHttpClient<ForecastHttpClient>(client =>
client.BaseAddress = new Uri("https://localhost:5001"));
コンポーネントによって型指定された HttpClient が挿入され、Web API が呼び出されます。
次のようなコンポーネント コードがあるとします。
- 前の
ForecastHttpClient
のインスタンスが挿入され、型指定された HttpClient を作成します。 - 型指定された HttpClient を使用して、 JSON の気象データの GET 要求が Web API から発行されます。
@inject ForecastHttpClient Http
...
@code {
private Forecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
forecasts = await Http.GetForecastAsync();
}
}
BlazorWebAppCallWebApi
サンプル アプリは、HttpClient コンポーネントで型指定されたCallTodoWebApiCsrTypedClient
を使用して Web API を呼び出す方法を示しています。 コンポーネントはInteractiveWebAssembly
を使用してクライアント側レンダリング (CSR) ( レンダリング モード) を採用しているため、型指定されたクライアント サービスの登録は、サーバー プロジェクトと Program
プロジェクトの両方の.Client
ファイルに表示されることに注意してください。
Cookie に基づく要求資格情報
このセクションのガイダンスは、認証 cookieに依存するクライアント側のシナリオに適用されます。
ベアラー トークン認証よりも安全性が高いとみなされる cookie ベースの認証では、構成済みの cookie で AddHttpMessageHandler を指定して DelegatingHandler を呼び出して、Web API 要求ごとに HttpClient 資格情報を送信できます。 ハンドラーは、SetBrowserRequestCredentials を使用して BrowserRequestCredentials.Include を構成します。これは、クロスオリジン要求を含む要求ごとに、Cookie や HTTP 認証ヘッダーなどの資格情報を送信するようにブラウザーに通知します。
CookieHandler.cs
:
public class CookieHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
request.Headers.Add("X-Requested-With", [ "XMLHttpRequest" ]);
return base.SendAsync(request, cancellationToken);
}
}
注記
AuthenticationStateProvider
からDelegatingHandler
にアクセスする方法のガイダンスについては、「ASP.NET Core サーバーサイドおよび追加のセキュリティ シナリオBlazor Web App」を参照してください。
CookieHandler
は、次のように Program
ファイルに登録されます。
builder.Services.AddTransient<CookieHandler>();
メッセージ ハンドラーは、HttpClient 認証を必要とするすべての構成済み cookie に次のように追加されます。
builder.Services.AddHttpClient(...)
.AddHttpMessageHandler<CookieHandler>();
デモについては、「ASP.NET Core Blazor WebAssembly を使用したセキュア ASP.NET Core Identity」を参照してください。
HttpRequestMessage を作成するときは、次のようにブラウザー要求の資格情報とヘッダーを直接設定します。
using var request = new HttpRequestMessage() { ... };
request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
request.Headers.Add("X-Requested-With", [ "XMLHttpRequest" ]);
HttpClient
と HttpRequestMessage
と Fetch API 要求オプション
このセクションのガイダンスは、ベアラー トークン認証に依存するクライアント側のシナリオに適用されます。
HttpClient
(API ドキュメント) と HttpRequestMessage を使用して、要求をカスタマイズできます。 たとえば、HTTP メソッドや要求ヘッダーを指定できます。 次のコンポーネントは、Web API エンドポイントに POST
要求を行い、応答本文を表示します。
TodoRequest.razor
:
@page "/todo-request"
@using System.Net.Http.Headers
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject HttpClient Http
@inject IAccessTokenProvider TokenProvider
<h1>ToDo Request</h1>
<h1>ToDo Request Example</h1>
<button @onclick="PostRequest">Submit POST request</button>
<p>Response body returned by the server:</p>
<p>@responseBody</p>
@code {
private string? responseBody;
private async Task PostRequest()
{
using var request = new HttpRequestMessage()
{
Method = new HttpMethod("POST"),
RequestUri = new Uri("https://localhost:10000/todoitems"),
Content =
JsonContent.Create(new TodoItem
{
Name = "My New Todo Item",
IsComplete = false
})
};
var tokenResult = await TokenProvider.RequestAccessToken();
if (tokenResult.TryGetToken(out var token))
{
request.Headers.Authorization =
new AuthenticationHeaderValue("Bearer", token.Value);
request.Content.Headers.TryAddWithoutValidation(
"x-custom-header", "value");
using var response = await Http.SendAsync(request);
var responseStatusCode = response.StatusCode;
responseBody = await response.Content.ReadAsStringAsync();
}
}
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
}
Blazorのクライアント側の実装はHttpClientを利用して、Fetch APIを使用し、リクエスト固有のFetch APIオプションをHttpRequestMessageの拡張メソッドおよびWebAssemblyHttpRequestMessageExtensionsで設定します。 汎用的な SetBrowserRequestOption 拡張メソッドを使用して、その他のオプションを設定できます。 Blazor と、基盤になる Fetch API は、要求ヘッダーを直接追加または変更しません。 ブラウザーなどのユーザー エージェントとヘッダーの対話方法の詳細については、外部ユーザー エージェントのドキュメント セットとその他の Web リソースを参照してください。
応答ストリーミングは既定で有効になっています。
HttpContent.ReadAsStreamAsync (HttpResponseMessage.Content) のresponse.Content.ReadAsStreamAsync()
を呼び出すと、BrowserHttpReadStream
ではなく、 が返されます。
BrowserHttpReadStream
では、 Stream.Read(Span<Byte>)
などの同期操作はサポートされていません。 コードで同期操作を使用している場合は、応答ストリーミングをオプトアウトするか、 Stream を自分で MemoryStream にコピーできます。
注記
通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[ 分岐またはタグの切り替え ] ドロップダウン リストを使用します。 詳細については、「 ASP.NET Core ソース コード (dotnet/AspNetCore.Docs #26205) のバージョン タグを選択する方法」を参照してください。
応答ストリーミングをグローバルにオプトアウトするには、次のいずれかの方法を使用します。
<WasmEnableStreamingResponse>
の値を持つプロジェクト ファイルにfalse
プロパティを追加します。<WasmEnableStreamingResponse>false</WasmEnableStreamingResponse>
DOTNET_WASM_ENABLE_STREAMING_RESPONSE
環境変数をfalse
または0
に設定します。
個々の要求の応答ストリーミングをオプトアウトするには、SetBrowserResponseStreamingEnabledをfalse
でHttpRequestMessageに設定します (次の例request
)。
request.SetBrowserResponseStreamingEnabled(false);
通常、HTTP 応答は、応答コンテンツでの同期読み取りのサポートを有効にするためにバッファリングされます。 応答ストリーミングのサポートを有効にするには、SetBrowserResponseStreamingEnabledをtrue
でHttpRequestMessageに設定します。
request.SetBrowserResponseStreamingEnabled(true);
既定では、 HttpCompletionOption.ResponseContentRead
が設定されているため、コンテンツを含む応答全体を読み取った後、 HttpClient が完了します。 大きなファイルで SetBrowserResponseStreamingEnabled オプションを使用できるようにするには、 HttpCompletionOption.ResponseHeadersRead
を設定して、ファイルのコンテンツをメモリにキャッシュしないようにします。
- using var response = await Http.SendAsync(request);
+ using var response = await Http.SendAsync(request,
+ HttpCompletionOption.ResponseHeadersRead);
クロスオリジン要求に資格情報を含めるには、SetBrowserRequestCredentials 拡張メソッドを使用します。
request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
Fetch API オプションの詳細については、 MDN Web ドキュメント「WindowOrWorkerGlobalScope.fetch(): Parameters」を参照してください。
エラーの処理
Web API 応答エラーの発生時には、開発者コードでエラーを処理します。 たとえば、GetFromJsonAsync では、Content-Type
が application/json
である Web API からの JSON 応答が想定されています。 応答が JSON 形式ではない場合、コンテンツ検証により NotSupportedException がスローされます。
次の例では、天気予報データ要求の URI エンドポイントのスペルが間違っています。 URI は WeatherForecast
である必要がありますが、呼び出しでは WeatherForcast
として表示されます。これには、e
に文字 Forecast
がありません。
GetFromJsonAsync の呼び出しでは、JSON が返されることが想定されていますが、Content-Type
が text/html
の未処理の例外について、Web API から HTML が返されます。
/WeatherForcast
へのパスが見つからず、ミドルウェアから要求のページまたはビューを提供できないため、未処理の例外が発生します。
クライアント上の OnInitializedAsync では、応答コンテンツが非 JSON であると検証されると NotSupportedException がスローされます。 例外は catch
ブロックでキャッチされます。ここで、カスタム ロジックを使用してエラーをログに記録したり、わかりやすいエラー メッセージをユーザーに表示したりすることができます。
ReturnHTMLOnException.razor
:
@page "/return-html-on-exception"
@using {PROJECT NAME}.Shared
@inject HttpClient Http
<h1>Fetch data but receive HTML on unhandled exception</h1>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<h2>Temperatures by Date</h2>
<ul>
@foreach (var forecast in forecasts)
{
<li>
@forecast.Date.ToShortDateString():
@forecast.TemperatureC ℃
@forecast.TemperatureF ℉
</li>
}
</ul>
}
<p>
@exceptionMessage
</p>
@code {
private WeatherForecast[]? forecasts;
private string? exceptionMessage;
protected override async Task OnInitializedAsync()
{
try
{
// The URI endpoint "WeatherForecast" is misspelled on purpose on the
// next line. See the preceding text for more information.
forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForcast");
}
catch (NotSupportedException exception)
{
exceptionMessage = exception.Message;
}
}
}
注記
前の例は、デモンストレーションを目的としています。 エンドポイントが存在しない場合や、未処理の例外がサーバー上で発生した場合でも、JSON を返すように Web API を構成できます。
詳細については、「 ASP.NET Core Blazor アプリでのエラーの処理」を参照してください。
クロスオリジン リソース共有 (CORS)
多くの場合、ブラウザーのセキュリティにより、Web ページが Web ページを提供した元とは異なる配信元への要求を行うことが制限されます。 この制限は、 同じ配信元ポリシーと呼ばれます。 同一オリジン ポリシーにより、悪意のあるサイトが別のサイトから機密データを読み取ることが制限されます (ただし、阻止されません)。 ブラウザーから別の配信元のエンドポイントに要求を行うには、 エンドポイント で クロスオリジン リソース共有 (CORS) を有効にする必要があります。
サーバー側 CORS の詳細については、「 ASP.NET Core でクロスオリジン要求 (CORS) を有効にする」を参照してください。 この記事の例は、Razor コンポーネント シナリオに直接関連していませんが、この記事は、一般的な CORS の概念を学習するために役立ちます。
クライアント側の CORS 要求の詳細については、「 ASP.NET Core Blazor WebAssembly 追加のセキュリティ シナリオ」を参照してください。
偽造防止サポート
HTTP 要求に偽造防止のサポートを追加するには、AntiforgeryStateProvider
を挿入し、ヘッダー コレクションに RequestToken
として RequestVerificationToken
を追加します。
@inject AntiforgeryStateProvider Antiforgery
private async Task OnSubmit()
{
var antiforgery = Antiforgery.GetAntiforgeryToken();
using var request = new HttpRequestMessage(HttpMethod.Post, "action");
request.Headers.Add("RequestVerificationToken", antiforgery.RequestToken);
using var response = await client.SendAsync(request);
...
}
詳細については、「 ASP.NET Core Blazor 認証と承認」を参照してください。
Web API アクセスのテストのための Blazor フレームワーク コンポーネントの例
Firefox Browser Developer など、Web API バックエンド アプリを直接テストするために、さまざまなネットワーク ツールが公開されています。 Blazor フレームワークの参照ソースには、テストに役立つ HttpClient テスト資産が含まれています。
HttpClientTest
dotnet/aspnetcore
GitHub リポジトリ内のアセット
注記
通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[ 分岐またはタグの切り替え ] ドロップダウン リストを使用します。 詳細については、「 ASP.NET Core ソース コード (dotnet/AspNetCore.Docs #26205) のバージョン タグを選択する方法」を参照してください。
その他のリソース
全般
- W3C でのクロスオリジン リソース共有 (CORS)
- ASP.NET Core でクロスオリジン要求 (CORS) を有効にする: コンテンツは Razor コンポーネントではなく、ASP.NET Core アプリに適用されますが、この記事では一般的な CORS の概念について説明します。
- Blazor Web App を用いて におけるデータをセキュリティで保護します。
- W3C でのクロスオリジン リソース共有 (CORS)
- ASP.NET Core でクロスオリジン要求 (CORS) を有効にする: コンテンツは Razor コンポーネントではなく、ASP.NET Core アプリに適用されますが、この記事では一般的な CORS の概念について説明します。
オーバーポスティング攻撃の防止
Web API は、大量割り当て攻撃とも呼ばれる過剰ポスティング攻撃に対して脆弱になる可能性があります。 オーバーポスト攻撃は、悪意のあるユーザーが、レンダリングされたフォームの一部ではなく、開発者がユーザーに修正を許可しないプロパティのデータを処理する HTML フォームの POST をサーバーに発行したときに発生します。 "オーバーポスティング" という用語は、文字どおり、悪意のあるユーザーがフォームで "過剰に" ポストすることを意味します。
オーバーポスト攻撃の軽減に関するガイダンスについては、「 チュートリアル: ASP.NET Core を使用してコントローラーベースの Web API を作成する」を参照してください。
サーバー側
- ASP.NET Core サーバー側と Blazor Web App 追加のセキュリティ シナリオ: セキュリティで保護された Web API 要求を行うために HttpClient を使用する方法について説明します。
- ASP.NET Core で IHttpClientFactory を使用して HTTP 要求を行う
- ASP.NET Core で HTTPS を適用する
- Kestrel HTTPS エンドポイントの構成
クライアント側
- ASP.NET Core Blazor WebAssembly 追加のセキュリティ シナリオ: HttpClient を使用してセキュリティで保護された Web API 要求を行う方法について説明します。
- ASP.NET Core で Graph API を使用する Blazor WebAssembly
- フェッチ API
ASP.NET Core