Note
這不是這篇文章的最新版本。 關於目前版本,請參閱 本文的 .NET 10 版本。
Warning
不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支持原則。 如需目前的版本,請參閱 本文的 .NET 9 版本。
本文說明如何從 Blazor 應用程式呼叫 Web API。
Package
System.Net.Http.Json 套件提供適用於 System.Net.Http.HttpClient 和 System.Net.Http.HttpContent 的擴充方法,這些方法會使用 System.Text.Json 來執行自動序列化及還原序列化。
System.Net.Http.Json 套件是由 .NET 共用架構所提供,且不需要將套件參考新增至應用程式。
使用令牌處理程序進行 Web API 呼叫
Blazor Web App具有 OIDC 驗證的服務可以使用令牌處理程式方法來提出傳出請求,以安全地調用外部 Web API。 本文<
如需詳細資訊,請參閱以下資源:
- ASP.NET Core 伺服器端和其他 Blazor Web App 安全性案例
- 使用 OpenID Connect (OIDC) 保護 ASP.NET Core Blazor Web App
Microsoft Web API 呼叫的身分識別平臺
Blazor Web App使用 Microsoft 身分識別平臺搭配 Microsoft Identity Web 套件以啟用 Microsoft Entra ID,可使用 Microsoft.Identity.Web.DownstreamApi NuGet 套件提供的 API 進行簡化的 Web API 呼叫。
在應用程式設定檔中 ,appsettings.json提供基底 URL 和範圍。 在下列範例中 {BASE ADDRESS} ,佔位符是Web API的基底URL。 指定單一範圍時,使用應用程式識別碼 URI({APP ID URI} 佔位符)和範圍名稱({SCOPE NAME} 佔位符):
"DownstreamApi": {
"BaseUrl": "{BASE ADDRESS}",
"Scopes": [ "{APP ID URI}/{SCOPE NAME}" ]
}
Example:
"DownstreamApi": {
"BaseUrl": "https://localhost:7277",
"Scopes": [ "api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get" ]
}
在應用程式的Program檔案中呼叫:
- EnableTokenAcquisitionToCallDownstreamApi:啟用存取令牌來呼叫 Web API。
-
AddDownstreamApi:Microsoft Identity Web 套件提供 API,以建立具名下游 Web 服務以進行 Web API 呼叫。 IDownstreamApi 會插入伺服器端類別,用來呼叫 CallApiForUserAsync 以從外部 Web API (MinimalApiJwt專案) 取得天氣數據。 - AddDistributedTokenCaches:將 .NET 分散式令牌快取新增至服務集合。
- AddDistributedMemoryCache:新增一個預設實作的IDistributedCache,將快取項目儲存在記憶體中。
- 設定分散式令牌快取選項 (MsalDistributedTokenCacheAdapterOptions):
- 在進行偵錯的開發中,您可以將 設定 DisableL1Cache 為
true來停用 L1 快取。 請務必將它重設為false以供正式使用。 - 設定 L1
L1CacheOptions.SizeLimit快取的大小上限,以防止快取佔用過多伺服器的記憶體。 預設值為 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)。
Note
若要在單一計算機上進行本機開發和測試,您可以使用記憶體內部令牌快取,而不是分散式令牌快取:
builder.Services.AddInMemoryTokenCaches();
稍後在開發和測試期間,採用生產分散式令牌快取提供者。
AddDistributedMemoryCache 新增了一個默認的 IDistributedCache 實作,將快取項目儲存在記憶體中,這用於Microsoft Identity Web的令牌快取。
AddDistributedMemoryCache需要引用Microsoft.Extensions.Caching.Memory NuGet 套件。
若要設定生產分散式快取提供者,請參閱 ASP.NET Core 中的分散式快取。
Warning
在將應用程式部署至生產環境時,務必將記憶體中的分散式令牌快取替換為實際運作的令牌快取提供者。 如果您無法採用生產分散式令牌快取提供者,應用程式可能會大幅降低效能。
如需詳細資訊,請參閱 令牌快取串行化:分散式快取。 不過,顯示的程式代碼範例不適用於 ASP.NET Core 應用程式,其會透過 AddDistributedMemoryCache設定分散式快取,而不是 AddDistributedTokenCache。
在生產環境中使用共用的數據保護密鑰圈,讓 Web 伺服器陣列中的應用程式實例在 MsalDistributedTokenCacheAdapterOptions.Encrypt 設定為 true 時可以解密令牌。
Note
若要在單一計算機上進行早期開發和本機測試,您可以稍後將 設定 Encrypt 為 false 並設定共用數據保護密鑰通道:
options.Encrypt = false;
稍後在開發和測試期間,啟用令牌加密,並採用共用數據保護密鑰通道。
下列範例示範如何針對共用金鑰環使用 Azure Blob 儲存體和 Azure Key Vault(PersistKeysToAzureBlobStorage/ProtectKeysWithAzureKeyVault)。 服務組態是用於示範的基底案例。 在部署生產應用程式之前,請先熟悉 Azure 服務,並使用本節結尾連結的 Azure 服務專用檔集來採用最佳做法。
將下列套件新增至 的伺服器 Blazor Web App專案:
Note
在繼續進行下列步驟之前,請先確認該應用程式已在 Microsoft Entra 註冊。
設定 Azure Blob 記憶體以維護資料保護密鑰。 請遵循 ASP.NET Core 中金鑰儲存提供者中的指引。
設定 Azure Key Vault 以加密靜態資料保護金鑰。 請遵循設定 ASP.NET Core Data Protection 中的指引。
在註冊服務的檔案中使用 Program 下列代碼:
TokenCredential? credential;
if (builder.Environment.IsProduction())
{
credential = new ManagedIdentityCredential("{MANAGED IDENTITY CLIENT ID}");
}
else
{
// Local development and testing only
DefaultAzureCredentialOptions options = new()
{
// Specify the tenant ID to use the dev credentials when running the app locally
// in Visual Studio.
VisualStudioTenantId = "{TENANT ID}",
SharedTokenCacheTenantId = "{TENANT ID}"
};
credential = new DefaultAzureCredential(options);
}
builder.Services.AddDataProtection()
.SetApplicationName("{APPLICATION NAME}")
.PersistKeysToAzureBlobStorage(new Uri("{BLOB URI}"), credential)
.ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);
{MANAGED IDENTITY CLIENT ID}:Azure 受控 Identity 用戶端標識碼 (GUID)。
{TENANT ID}:租使用者標識碼。
{APPLICATION NAME}: SetApplicationName 設定資料保護系統中此應用程式的唯一名稱。 應用程式部署間的值應保持一致。
{BLOB URI}:金鑰檔案的完整 URI。 當您建立密鑰檔案時,Azure 記憶體會產生 URI。 禁止使用 SAS。
{KEY IDENTIFIER}:用於密鑰加密的 Azure Key Vault 金鑰標識碼。 存取原則可讓應用程式使用 Get、 Unwrap Key和 Wrap Key 許可權存取金鑰保存庫。 創建後,可從 Entra 或 Azure 入口網站的密鑰中獲取密鑰標識碼。 如果您啟用金鑰儲存庫金鑰的自動調整,請確定您在應用程式的金鑰儲存庫組態中使用無版本金鑰標識碼,其中識別子結尾不會放置任何金鑰 GUID(例如:)。 https://contoso.vault.azure.net/keys/data-protection
Note
在非生產環境中,上述範例會使用 DefaultAzureCredential 來簡化驗證,同時開發部署至 Azure 的應用程式,方法是將 Azure 主控環境中所使用的認證與本機開發中使用的認證結合在一起。 移至生產環境時,替代方式是較佳的選擇,例如 ManagedIdentityCredential 上述範例所示的 。 如需詳細資訊,請參閱 使用系統指派的受控識別向 Azure 資源驗證 Azure 裝載的 .NET 應用程式。
代表使用者呼叫 時插入 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!");
}
}
本文<
如需詳細資訊,請參閱以下資源:
- ASP.NET Core 中的金鑰儲存體提供者
- 設定核心數據保護 ASP.NET
- 在 ASP.NET Core 應用程式中使用 Azure SDK for .NET
- Web API 檔 |Microsoft身分識別平臺
- 呼叫 Web API 的 Web API:呼叫 API:選項 2:使用協助程序類別呼叫下游 Web API
- IDownstreamApi
- 使用 Microsoft Entra 識別碼保護 ASP.NET Core Blazor Web App
- 在 Web 農場中託管 ASP.NET Core:資料保護
- Azure Key Vault 文件
- Azure 儲存體文件
- 使用 Azure 角色型訪問控制來提供 Key Vault 金鑰、憑證和秘密的存取權
範例應用程式
如需運作範例,請參閱 GitHub 存放庫 () 範例中的Blazor下列範例應用程式(dotnet/blazor-samples如何下載)。
BlazorWebAppCallWebApi
從 Blazor Web App 呼叫外部(不在Blazor Web App)的待辦事項清單 Web API:
-
Backend:Web API 應用程式,可根據 最小 API 維護 Todo 清單。 Web API 應用程式是與 Blazor Web App不同的應用程式,可能託管於不同的伺服器。 -
BlazorApp/BlazorApp.Client:這個 Blazor Web App 使用 HttpClient 來呼叫 Web API 應用程式,執行待辦事項清單的作業,比如建立、讀取、更新和刪除(CRUD)項目。
針對用戶端轉譯 (CSR),其中包含採用 CSR 的互動式 WebAssembly 組件和 Auto 組件,將會使用預先配置的 HttpClient,此配置已在用戶端專案 (Program) 的 BlazorApp.Client 檔案中註冊。
builder.Services.AddScoped(sp =>
new HttpClient
{
BaseAddress = new Uri(builder.Configuration["FrontendUrl"] ??
"https://localhost:5002")
});
針對伺服器端渲染 (SSR),其中包括預先渲染和互動式的伺服器元件、WebAssembly 預先渲染元件,以及預先渲染或採用了 SSR 的 Auto 元件,在伺服器專案 (HttpClient) 的 Program 檔案中註冊的 BlazorApp 進行呼叫:
builder.Services.AddHttpClient();
呼叫內部 (位於 Blazor Web App) 的電影清單 API,其中該 API 位於 Blazor Web App 的伺服器專案中:
-
BlazorApp:維護著電影清單的 Blazor Web App- 在伺服器的應用程式中對電影清單進行操作時,使用的是一般的 API 呼叫。
- 當以 Web 為基礎的用戶端進行 API 呼叫時,Web API 會根據 精簡 API 用來進行電影列表操作。
-
BlazorApp.Client:Blazor Web App的客戶端專案,其中包含用於管理電影清單使用者的互動式 WebAssembly 和 Auto 元件。
針對已採用 CSR 的互動式 WebAssembly 元件和 Auto 元件,API 呼叫是透過使用者端型服務 (ClientMovieService) 進行,該服務使用的是註冊在用戶端專案的 HttpClient 檔案(Program) 中已預先設定的 BlazorApp.Client。 由於這些呼叫是透過公用或私人 Web 進行,電影清單 API 是 Web API。
下列範例會從 /movies 端點取得電影清單:
public class ClientMovieService(HttpClient http) : IMovieService
{
public async Task<Movie[]> GetMoviesAsync(bool watchedMovies) =>
await http.GetFromJsonAsync<Movie[]>("movies") ?? [];
}
針對 SSR,其中包含預先轉譯和互動式伺服器元件、預先轉譯的 WebAssembly 元件,以及預先轉譯或採用 SSR 的 Auto 元件,呼叫是直接透過伺服器型服務 (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();
}
如需有關如何在此案例中保護電影數據的詳細資訊,請參閱在互動式自動 rendering 中保護數據所描述的天氣數據Blazor Web App範例。
BlazorWebAppCallWebApi_Weather
天氣資料應用程式範例,使用串流轉譯處理天氣資料。
BlazorWebAssemblyCallWebApi
從 Blazor WebAssembly 應用程式呼叫待辦事項清單 Web API:
-
Backend:Web API 應用程式,可根據 最小 API 維護 Todo 清單。 -
BlazorTodo:一個 Blazor WebAssembly 應用程式,使用預先設定的 HttpClient 呼叫 web API,執行待辦事項清單的 CRUD 作業。
BlazorWebAssemblyStandaloneWithIdentity
使用 ASP.NET Core Blazor WebAssembly保護的獨立 Identity 應用程式:
-
Backend:維護 ASP.NET Core Identity使用者身分識別存放區的後端 Web API 應用程式。 -
BlazorWasmAuth:具有使用者驗證的獨立 Blazor WebAssembly 前端應用程式。
此解決方案示範如何針對下列專案呼叫安全的 Web API:
BlazorWebAppOidc
具有全球自動互動性的 Blazor Web App,透過 Microsoft Entra 使用 OIDC 認證,而不需使用 Entra 特定的套件。 此範例示範如何使用 Web API 呼叫的令牌處理程式 來呼叫外部安全 Web API。
BlazorWebAppOidcServer
使用 OIDC 驗證和 Microsoft Entra 實現的 Blazor Web App,具備全球互動式伺服器的互動性,且不需依賴 Entra 特定的套件。 此範例示範如何 傳遞存取令牌 來呼叫外部安全 Web API。
BlazorWebAppOidcBff
具有全域自動互動功能的 Blazor Web App,其使用:
- 使用 Microsoft Entra 進行 OIDC 驗證,而不需使用 Entra 特定的套件。
- 前端專屬後端(BFF)模式,這是應用程式開發的一種模式,專門為前端應用程式或介面建立後端服務。
解決方案包含示範如何在用戶端轉譯採用互動自動渲染的元件時,透過外部 Web API 安全地獲取天氣資料。
BlazorWebAppEntra
Blazor Web App具有全域自動互動性,使用Microsoft 身分識別平台與Microsoft Identity Web 套件搭配Microsoft Entra ID。 解決方案包含示範如何在用戶端轉譯採用互動自動渲染的元件時,透過外部 Web API 安全地獲取天氣資料。
BlazorWebAppEntraBff
具有全域自動互動功能的 Blazor Web App,其使用:
- Microsoft 身分識別平臺與 Microsoft Web 套件,適用於 Microsoft Entra ID。
- 前端專屬後端(BFF)模式,這是應用程式開發的一種模式,專門為前端應用程式或介面建立後端服務。
解決方案包含示範如何在用戶端轉譯採用互動自動渲染的元件時,透過外部 Web API 安全地獲取天氣資料。
HttpRequestMessage、HttpResponseMessage 和 HttpClient 的處置
沒有屍體不需要 HttpRequestMessage 明確處置。 不過,您可以使用下列其中一種模式來處置它:
using宣告(C# 8 或更新版本):using var request = new HttpRequestMessage(...);-
using (var request = new HttpRequestMessage(...)) { ... }
我們建議每次使用時都丟棄每個 HttpRequestMessage ,原因如下:
- 若要透過避免使用終結器來提升效能。
- 它將強化程式碼,以便未來如果在起初沒有要求主體的 HttpRequestMessage 中新增請求正文時,能夠處理。
- 如果委派處理程式預期呼叫 Dispose/DisposeAsync,可能會避免功能問題。
- 在任何地方套用一般規則比嘗試記住特定案例更簡單。
一律 清除 HttpResponseMessage 實例。
絕對不要 處置 HttpClient 藉由呼叫 CreateClient 所建立的實例,因為它們是由架構所管理。
Example:
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元件會向適用於 GitHub 的 Web API 分支提出要求,類似於在 ASP.NET Core 中使用 IHttpClientFactory 進行 HTTP 要求中的基本使用範例一文。
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 數據保護 功能搭配伺服器端 ASP.NET Core 後端 Web API。 用戶端 Blazor WebAssembly 應用程式會呼叫伺服器端 Web API,以保護應用程式功能和數據處理。
由於 Blazor WebAssembly, 應用程式通常無法跨來源對 Web API 進行直接呼叫。 典型的例外狀況如下所示:
從來源 'https://localhost:{PORT}'' 嘗試存取 '{URL}' 時被 CORS 原則封鎖:請求的資源上缺少 'Access-Control-Allow-Origin' 標頭。 如果無法透明化的回應符合您的需求,請將請求的模式設定為『no-cors』,以取得禁用 CORS 的資源。
即使您嘗試呼叫 SetBrowserRequestMode 並在 BrowserRequestMode 欄位中使用 NoCors(1)來規避前述例外情況,由於 CORS 對 Web API 的來源限制,請求通常仍然會失敗,例如限制只允許來自特定來源的呼叫,或限制防止瀏覽器中的 JavaScript fetch 請求。 若要讓這類呼叫成功,唯一的方法是您所呼叫的 Web API 必須允許您的來源,使用正確配置的 CORS 組態來呼叫其來源。 大部分的外部 Web API 都不允許您設定其 CORS 原則。 若要處理這項限制,請採用下列任一策略:
維護您自己的伺服器端 ASP.NET Core 後端 Web API。 用戶端 Blazor WebAssembly 應用程式會呼叫伺服器端 Web API,而您的 Web API 會使用正確的 CORS 標頭,從其伺服器型 C# 程式代碼(而非瀏覽器)向外部 Web API 提出要求,並將結果傳回至用戶端 Blazor WebAssembly 應用程式。
使用代理服務將用戶端 Blazor WebAssembly 應用程式的請求代理轉發至外部的 Web API。 Proxy 服務會使用伺服器端應用程式代表用戶端提出要求,並在呼叫成功之後傳回結果。 在以下以 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 服務。 使用 HttpClientHttpClient 工廠基礎設施向應用程式提供 。
在 Program 檔案中:
builder.Services.AddHttpClient();
下列Razor元件會向適用於 GitHub 的 Web API 分支提出要求,類似於在 ASP.NET Core 中使用 IHttpClientFactory 進行 HTTP 要求中的基本使用範例一文。
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 呼叫的服務抽象層
本節適用於 Blazor Web App在伺服器項目中維護 Web API,或轉換 Web API 呼叫至外部 Web API 的 。
使用互動式 WebAssembly 和自動轉譯模式時,預設會預先轉譯元件。 Auto 元件一開始也會以互動方式從伺服器轉譯,然後 Blazor 套件組合便下載至用戶端,並啟動用戶端執行階段。 這表示使用這些轉譯模式的元件,應該設計為可以從客戶端和伺服器順利執行。 如果在用戶端執行時,元件必須呼叫伺服器專案型 API,或將要求轉換為外部 Web API (位於 Blazor Web App外部),建議將服務介面後方的 API 呼叫抽象化,並實作服務的用戶端和伺服器版本:
- 用戶端版本會使用預先設定的 HttpClient 呼叫 Web API。
- 伺服器版本通常可以直接存取伺服器端資源。 不建議在伺服器上插入會呼叫回伺服器的 HttpClient,因為這樣的網路請求通常是不必要的。 或者,API 可能位於伺服器專案之外,但伺服器需要一個服務抽象層來以某種方式轉換請求,例如在代理請求中新增一個存取權杖。
使用 WebAssembly 轉譯模式時,您也可以選擇停用預先轉譯,讓元件只從用戶端轉譯。 如需詳細資訊,請參閱 Prerender ASP.NET Core Razor 元件。
範例(範例應用程式):
-
BlazorWebAppCallWebApi應用程式範例中的電影清單 Web API。 - 在
BlazorWebAppCallWebApi_Weather範例應用程式中,實現即時串流渲染的天氣數據網路 API。 - 回傳至用戶端的天氣資料,會在
BlazorWebAppOidc(非 BFF 模式)或BlazorWebAppOidcBff(BFF 模式)的應用程式範例中出現。 這些應用程式示範安全的 (web) API 呼叫。 如需詳細資訊,請參閱使用 OpenID Connect 保護 ASP.NET Core Blazor Web App (OIDC)。
Blazor Web App 外部 Web API
本節適用於 Blazor Web App呼叫由另一個(外部)專案維護的 Web API,可能裝載在不同的伺服器上。
Blazor Web App通常會在用戶端預先轉譯 WebAssembly 元件,而 Auto 元件則會在伺服器上執行靜態或互動式伺服器端呈現 (SSR) 時進行轉譯。
HttpClient 服務預設不會在 Blazor Web App的主要專案註冊。 如果應用程式僅執行在HttpClient專案中註冊的.Client服務,如新增HttpClient服務一節所述,那麼執行應用程式將會導致運行時錯誤:
InvalidOperationException:無法為類型為 '...{COMPONENT}' 的屬性 'Http' 提供值。 沒有類型為 'System.Net.Http.HttpClient' 的已註冊服務。
使用下列 其中一 種方法:
將 HttpClient 服務新增至伺服器專案,以讓 HttpClient 在 SSR 過程中可用。 在伺服器計畫的
Program檔案中,使用下列服務註冊:builder.Services.AddHttpClient();HttpClient 服務由共用架構提供,因此不需要應用程式專案檔中的套件參考。
如果呼叫 Web API 的 WebAssembly 元件不需要預先呈現,請遵循 Prerender ASP.NET Core Razor 元件中的指引來停用預先呈現。 如果您採用這個方法,則不需要將 HttpClient 服務新增至 Blazor Web App 的主要專案,因為不會在伺服器預先解譯元件。
如需詳細資訊,請參閱 Prerendering 一文的用戶端服務無法在預先呈現期間解決。
預渲染資料
預先轉譯時,元件會轉譯兩次:先以靜態方式轉譯,然後以互動方式轉譯。 狀態不會自動從預先轉譯的元件流向互動式元件。 如果元件執行非同步初始化作業,並在初始化期間轉譯不同狀態的不同內容,例如「載入中...」進度指示器,則元件轉譯兩次時,您可能會看到閃爍。
您可以透過使用持續性元件狀態 API 來傳遞預渲染狀態,以解決此問題,這可以在 BlazorWebAppCallWebApi 和 BlazorWebAppCallWebApi_Weather範例應用程式 中看到示範。 元件以互動方式呈現時,可以用相同的狀態以相同的方式呈現。 如需詳細資訊,請參閱以下資源:
Note
持續性元件狀態 API 僅支援 .NET 10 或更新版本中的增強型導覽。 針對以 .NET 8 或 .NET 9 為目標的應用程式,您可以在連結到屬性設定為 data-enhance-navfalse 的頁面上停用增強型導覽。 如需詳細資訊,請參閱 ASP.NET Core Blazor 路由和瀏覽。
用戶端請求串流
針對以 Chromium 為基礎的瀏覽器(例如 Google Chrome 和 Microsoft Edge),使用 HTTP/2 通訊協定和 HTTPS,用戶端 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 選項配置。
唯有針對應用程式中單一 HttpClient 執行個體呼叫單一 Web API 時,本節的設定範例才有用。 應用程式必須呼叫多個 Web API 時,每個 API 都有自己的基底位址 (Base Address) 和設定,您可以採用本文稍後會說明的下列方法:
-
命名
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 標籤的值獲得。
使用用戶端本身基底位址 (Base Address) 最常見的使用案例如下:
-
.Client(.NET 8 或更新版本) 的用戶端專案 (Blazor Web App) 會從 WebAssembly 元件,或是從在 WebAssembly 用戶端執行的程式碼,向伺服器應用程式中的 API 進行 Web API 呼叫。 - 裝載 Client 應用程式的用戶端專案 (Blazor WebAssembly) 會向伺服器專案 (Server) 進行 Web API 呼叫。 請注意,.NET 8 或更新版本不再提供裝載 Blazor WebAssembly 項目範本。 不過,.NET 8 仍支援裝載 Blazor WebAssembly 的應用程式。
如果您要呼叫外部 Web API (不在與用戶端應用程式相同的 URL 空間),請將 URI 設定為 Web API 的基底位址 (Base Address)。 下列範例會將 Web API 的基底位址 (Base Address) 設定為 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指令將@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");
POST 請求格式為 JSON(PostAsJsonAsync)
PostAsJsonAsync 會將 POST 請求傳送至指定的 URI,請求本文中包含以 JSON 序列化的值。
在下列元件程式碼中,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 是由元件的繫結元素所提供。 當項目在 UI 的另一個部分被選取 (未顯示) 且呼叫 Id 時,會設定項目的 EditItem。 選取 SaveItem 元素會觸發 <button> 方法。 為了簡潔,下列範例不顯示載入 todoItems。 如需載入項目的範例,請參閱 GET from JSON (GetFromJsonAsync) 一節。
await Http.PutAsJsonAsync($"todoitems/{editItem.Id}", editItem);
PutAsJsonAsync 會傳回 HttpResponseMessage。 若要從回應訊息還原序列化 JSON 內容,請使用 ReadFromJsonAsync 擴充方法。 下列範例會以陣列的形式讀取 JSON 天氣資料:
var content = await response.Content.ReadFromJsonAsync<WeatherForecast[]>() ??
Array.Empty<WeatherForecast>();
將 PATCH 作為 JSON(PatchAsJsonAsync)
PatchAsJsonAsync 傳送具有 JSON 編碼內容的 HTTP 修補檔要求。
Note
如需詳細資訊,請參閱 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 字串撰寫為 原始字串常值。 針對程式碼分析工具,請使用 JSON 語法將 StringSyntaxAttribute.Json 欄位指定為 屬性的 [StringSyntax]。
@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 待辦事項資料讀取為陣列。 如果這個方法沒有傳回事項資料,則會建立空陣列,因此 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
}
]
為了簡化在發出修補檔要求的應用程式中建立修補檔文件的程序,應用程式可以使用 .NET JSON 修補檔支援,如下列指導所示。
安裝 Microsoft.AspNetCore.JsonPatch.SystemTextJson NuGet 套件,並使用套件的 API 功能來撰寫 PATCH 要求的 JsonPatchDocument。
請將 @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。
將 @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 並不會影響處理修補檔要求,且通常不會在 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 應用程式。
Note
不需要將 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.NotFound();
});
Warning
如同 ASP.NET Core Web API 文章中 JsonPatch 中的其他範例,上述 PATCH API 不會保護 Web API 免於過度發佈攻擊。 如需詳細資訊,請參閱 教學課程:使用 ASP.NET Core 建立控制器型 Web API。
如需完整運作的 PATCH 體驗,請參閱 BlazorWebAppCallWebApi範例應用程式。
刪除 (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 的組態。
Note
使用 HttpClient 中具名 IHttpClientFactory 的替代方法是使用型別化的 HttpClient。 如需詳細資訊,請參閱 Typed HttpClient 一節。
將 Microsoft.Extensions.Http NuGet 套件新增至應用程式。
在客戶專案的Program檔案中:
builder.Services.AddHttpClient("WebAPI", client =>
client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));
如果命名的用戶端要由預先轉譯的 Blazor Web App 用戶端元件使用,那麼服務註冊應該同時出現在伺服器專案和 .Client 專案中。 在伺服器上,builder.HostEnvironment.BaseAddress 會由 Web API 的基底位址 (Base Address) 取代,如下所述。
上述用戶端範例會使用 builder.HostEnvironment.BaseAddress 和 IWebAssemblyHostEnvironment.BaseAddress 設定基底位址,這樣即可取得用戶端應用程式的基底位址,而且通常是從主頁面 <base> 標籤的 href 值衍生出來的。
使用用戶端本身基底位址 (Base Address) 最常見的使用案例如下:
-
.Client的用戶端專案 (Blazor Web App) 會透過 WebAssembly/Auto 組件,或在 WebAssembly 中用戶端執行的程式碼,對相同主機位址伺服器應用程式的 API 進行 Web API 呼叫。 - 裝載 Client 應用程式的用戶端專案 (Blazor WebAssembly) 會向伺服器專案 (Server) 進行 Web API 呼叫。
使用用戶端本身基底位址 (Base Address) 最常見的使用案例,是在裝載 Client 應用程式的用戶端專案 (Blazor WebAssembly) 中,對伺服器專案 (Server) 進行 Web API 呼叫。
如果您要呼叫外部 Web API (不在與用戶端應用程式相同的 URL 空間),或是在伺服器端應用程式設定服務 (例如處理伺服器用戶端元件的預先解譯),請將 URI 設定為 Web API 的基底位址 (Base Address)。 下列範例會將 Web API 的基底位址 (Base Address) 設定為 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 元件中使用具名 來呼叫 Web API。 如需在用戶端應用程式中展示更多以命名為HttpClient的 Microsoft Graph 為基礎的工作示範,請參閱使用 ASP.NET Core 搭配 Graph APIBlazor WebAssembly。
如需以呼叫具名 HttpClient的 Microsoft Graph 為基礎的用戶端應用程式中運作示範,請參閱搭配 ASP.NET Core Blazor WebAssembly使用 Graph API。
已輸入HttpClient
具型別的 HttpClient 會使用應用程式的一個或多個 HttpClient 實例(預設或具名),以從一個或多個 Web API 端點取得資料。
Note
作為使用具型別的 HttpClient 的替代方法,可以使用來自 HttpClient 的具名 IHttpClientFactory。 如需詳細資訊,請參閱 具名的HttpClient 和 IHttpClientFactory 部分。
將 Microsoft.Extensions.Http NuGet 套件新增至應用程式。
以下範例發出來自 Web API 於 /forecast之 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 的基底位址 (Base Address) 取代,如下所述。
上述範例會使用 builder.HostEnvironment.BaseAddress (IWebAssemblyHostEnvironment.BaseAddress) 來設定基底位址,這用來取得用戶端應用程式的基底位址,通常會源自於主機頁面 <base> 標籤的 href 值。
使用用戶端本身基底位址 (Base Address) 最常見的使用案例如下:
-
.Client的用戶端專案 (Blazor Web App) 會透過 WebAssembly/Auto 組件,或在 WebAssembly 中用戶端執行的程式碼,對相同主機位址伺服器應用程式的 API 進行 Web API 呼叫。 - 裝載 Client 應用程式的用戶端專案 (Blazor WebAssembly) 會向伺服器專案 (Server) 進行 Web API 呼叫。
使用用戶端本身基底位址 (Base Address) 最常見的使用案例,是在裝載 Client 應用程式的用戶端專案 (Blazor WebAssembly) 中,對伺服器專案 (Server) 進行 Web API 呼叫。
如果您要呼叫外部 Web API (不在與用戶端應用程式相同的 URL 空間),或是在伺服器端應用程式設定服務 (例如處理伺服器用戶端元件的預先解譯),請將 URI 設定為 Web API 的基底位址 (Base Address)。 下列範例會將 Web API 的基底位址 (Base Address) 設定為 https://localhost:5001,其中會執行個別的 Web API 應用程式,並準備好回應來自用戶端應用程式的要求:
builder.Services.AddHttpClient<ForecastHttpClient>(client =>
client.BaseAddress = new Uri("https://localhost:5001"));
元件會將具型別的HttpClient 插入,以呼叫 Web API。
在下列元件程式碼中:
- 會注入前述
ForecastHttpClient的一個實例,從而建立具型別的 HttpClient。 - 這個輸入的 HttpClient 用於從 Web API 發出 GET 請求以獲取 JSON 天氣預報資料。
@inject ForecastHttpClient Http
...
@code {
private Forecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
forecasts = await Http.GetForecastAsync();
}
}
範例BlazorWebAppCallWebApi應用程式示範如何呼叫具有其HttpClient元件中具型別CallTodoWebApiCsrTypedClient的Web API。 請注意,元件採用了用戶端轉譯(CSR)(InteractiveWebAssembly 轉譯模式)並且支持預渲染,因此類型化的用戶端服務註冊會出現在伺服器專案的 Program 檔案和 .Client 專案的檔案中。
Cookie為基礎的請求憑證
本節中的指引適用於依賴驗證 cookie的用戶端案例。
針對被視為比持有人權杖驗證更安全的 cookie 型驗證,可以針對每個 Web API 請求,利用預先設定的 cookie 上的 AddHttpMessageHandler 呼叫 DelegatingHandler 來傳送 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);
}
}
Note
如需如何從AuthenticationStateProvider存取 DelegatingHandler 的指引,請參閱 ASP.NET Core 伺服器端和其他Blazor Web App安全性案例。
CookieHandler 會在 Program 檔案中註冊:
builder.Services.AddTransient<CookieHandler>();
訊息處理程式會新增至任何需要 HttpClient 驗證的預先設定 cookie:
builder.Services.AddHttpClient(...)
.AddHttpMessageHandler<CookieHandler>();
撰寫 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,並透過 擴充方法和 HttpRequestMessage 配置底層的 WebAssemblyHttpRequestMessageExtensions。 使用泛型 SetBrowserRequestOption 擴充方法來設定其他選項。 Blazor 和 Fetch API 不會直接新增或修改請求標頭。 如需有關使用者代理程式(例如瀏覽器)如何與標頭互動的詳細資訊,請參閱外部使用者代理程式文件集和其他 Web 資源。
默認會啟用回應串流。
調用 HttpContent.ReadAsStreamAsync 為 HttpResponseMessage.Content(response.Content.ReadAsStreamAsync())會返回BrowserHttpReadStream(參考來源),而不是 MemoryStream。
BrowserHttpReadStream 不支援同步作業,例如 Stream.Read(Span<Byte>)。 如果您的程式碼使用同步作業,您可以選擇不使用回應串流,或自行將 Stream 複製到 MemoryStream。
Note
.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);
如需擷取 API 選項的詳細資訊,請參閱 MDN Web 檔:WindowOrWorkerGlobalScope.fetch(): 參數。
處理錯誤
當在開發人員程式碼中發生 Web API 回應錯誤時,進行錯誤處理。 例如,GetFromJsonAsync 預期從 Web API 取得格式為 Content-Type 的 application/json 的 JSON 回應。 如果回應不是 JSON 格式,則內容驗證會擲回 NotSupportedException。
在下列範例中,天氣預報資料要求的 URI 端點拼錯。 URI 應為 WeatherForecast,但在呼叫中顯示為 WeatherForcast,其中遺漏 e 中的字母 Forecast。
GetFromJsonAsync 呼叫預期會傳回 JSON,但對於未處理的例外狀況,Web API 傳回的是帶有 Content-Type 的 text/html 的 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;
}
}
}
Note
上述範例僅供示範之用。 即使端點不存在或伺服器上發生未處理的例外狀況,Web API 仍可設定為傳回 JSON。
如需詳細資訊,請參閱 處理 ASP.NET Core Blazor 應用程式中的錯誤。
跨來源資源共用 (CORS)
瀏覽器安全性通常會限制網頁向提供網頁的不同來源提出要求。 這項限制稱為 相同原始原則。 相同來源原則會限制 (但不會防止) 惡意網站從另一個網站讀取敏感性資料。 若要從瀏覽器向不同來源的網域端點提出要求,端點必須啟用跨來源資源共享(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 核心 Blazor 驗證和授權。
測試 Web API 存取的 Blazor 架構元件範例
各種網路工具可公開用於直接測試 Web API 後端應用程式,例如 Firefox 瀏覽器開發人員。 Blazor 架構的參考來源包含可用於測試的 HttpClient 測試資產:
HttpClientTest GitHub 存放 dotnet/aspnetcore 庫中的資產
Note
.NET 參考來源的文件連結通常會載入存放庫的預設分支,該分支代表針對下一版 .NET 的當前開發。 若要選取特定發行版本的標籤,請使用「切換分支或標籤」下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼的版本標記(dotnet/AspNetCore.Docs #26205)。
其他資源
General
- W3C 的跨原始來源資源分享 (CORS)
- 在 ASP.NET Core 中啟用跨原始來源要求(CORS:雖然內容適用於 ASP.NET 核心應用程式,而非 Razor 元件,但本文涵蓋一般 CORS 概念。
- 在Blazor Web App秒內保護數據,使用互動式自動轉譯
- W3C 的跨原始來源資源分享 (CORS)
- 在 ASP.NET Core 中啟用跨原始來源要求(CORS:雖然內容適用於 ASP.NET 核心應用程式,而非 Razor 元件,但本文涵蓋一般 CORS 概念。
降低過度發佈攻擊的風險
Web API 可能容易受到「過度發佈」攻擊,其也稱為「大量指派」攻擊。 當惡意使用者向伺服器發出 HTML 表單 POST 要求,而該伺服器處理的資料屬於未在呈現的表單中顯示的屬性,且開發人員不希望使用者修改這些屬性時,就會發生過度提交攻擊。 「過度發佈」一詞的字面意思是指惡意使用者使用表單進行過多的 POST 操作。
如需緩解過度發佈攻擊的指引,請參閱 教學課程:使用 ASP.NET Core 建立控制器型 Web API。
Server-side
- Blazor Web App:包括如何使用來進行安全的 Web API 請求。
- 在 ASP.NET Core 中使用 IHttpClientFactory 提出 HTTP 要求
- 在 ASP.NET Core 中強制執行 HTTPS
- Kestrel HTTPS 端點組態
Client-side
- ASP.NET 核心 Blazor WebAssembly 其他安全性案例:包含使用 HttpClient 進行安全 Web API 要求的涵蓋範圍。
- 搭配 ASP.NET Core 使用 Graph API Blazor WebAssembly
- 擷取