從 ASP.NET Core 呼叫 Web API Blazor
注意
這不是這篇文章的最新版本。 如需目前版本,請參閱本文的 .NET 8 版本。
警告
不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支援原則。 如需目前版本,請參閱本文的 .NET 8 版本。
本文說明如何從 Blazor 應用程式呼叫 Web API。
套件
System.Net.Http.Json
套件提供適用於 System.Net.Http.HttpClient 和 System.Net.Http.HttpContent 的擴充方法,這些方法會使用 System.Text.Json
來執行自動序列化及還原序列化。 System.Net.Http.Json
套件是由 .NET 共用架構所提供,且不需要將套件參考新增至應用程式。
範例應用程式
請參閱 dotnet/blazor-samples
GitHub 存放庫中的應用程式範例。
BlazorWebAppCallWebApi
從 Blazor Web App呼叫外部 (不在 Blazor Web App) 待辦事項清單 Web API:
Backend
:Web API 應用程式,可根據 最小 API 維護待辦事項清單。 Web API 應用程式是與 Blazor Web App不同的應用程式,可能託管於不同的伺服器。BlazorApp
/BlazorApp.Client
:這個 Blazor Web App 使用 HttpClient 為待辦事項清單作業呼叫 Web API 應用程式,例如從待辦事項清單建立、讀取、更新和刪除 (CRUD) 項目。
針對用戶端轉譯 (CSR),其中包含已採用 CSR 的互動式 WebAssembly 元件和 Auto 元件,呼叫使用的是在用戶端專案 (BlazorApp.Client
) Program
檔案註冊之預先設定的 HttpClient:
builder.Services.AddScoped(sp =>
new HttpClient
{
BaseAddress = new Uri(builder.Configuration["FrontendUrl"] ?? "https://localhost:5002")
});
針對伺服器端轉譯 (SSR),其中包含預先轉譯和互動式伺服器元件、預先轉譯的 WebAssembly 元件,以及預先轉譯或採用 SSR 的 Auto 元件,呼叫使用的是在伺服器專案 (BlazorApp
) Program
檔案中註冊的 HttpClient:
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,其中包含已採用 CSR 的互動式 WebAssembly 元件和 Auto 元件,呼叫 API 是透過用戶端型服務 (ClientMovieService
) 進行,使用的是在用戶端專案 (BlazorApp.Client
) Program
檔案註冊之預先設定的 HttpClient。 由於這些呼叫是透過公用或私人 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();
}
BlazorWebAppCallWebApi_Weather
天氣資料應用程式範例,使用串流轉譯處理天氣資料。
BlazorWebAssemblyCallWebApi
從 Blazor WebAssembly 應用程式呼叫待辦事項清單 Web API:
Backend
:Web API 應用程式,可根據 最小 API 維護待辦事項清單。BlazorTodo
:這個 Blazor WebAssembly 應用程式使用預先設定的 HttpClient,為執行待辦事項清單 CRUD 作業呼叫 Web API。
呼叫外部 Web API 的伺服器端案例
以伺服器為基礎的元件會使用 HttpClient 執行個體 (通常是使用 IHttpClientFactory 所建立) 呼叫外部 Web API。 如需適用於伺服器端應用程式的指引,請參閱在 ASP.NET Core 中使用 IHttpClientFactory 提出 HTTP 要求。
伺服器端應用程式不包含 HttpClient 服務。 使用 HttpClient
處理站基礎結構向應用程式提供 HttpClient。
在 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 Blazor Server 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()
{
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();
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
變數建立空陣列 ([]
)。 針對舊版 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 可能位於伺服器專案外部,但伺服器需要服務抽象概念,才能以某種方式轉換要求,例如將存取權杖新增至 Proxy 的要求。
使用 WebAssembly 轉譯模式時,您也可以選擇停用預先轉譯,讓元件只從用戶端轉譯。 如需詳細資訊,請參閱 ASP.NET Core Blazor 轉譯模式。
範例 (應用程式範例):
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
本章節適用於 Blazor Web App,該程式會呼叫個別 (外部) 專案維護的 Web API (可能託管於不同的伺服器)。
Blazor Web App通常會預先轉譯用戶端 WebAssembly 元件,而 Auto 元件則是在靜態或互動式伺服器端轉譯 (SSR) 期間於伺服器轉譯。 HttpClient 服務預設不會在 Blazor Web App的主要專案註冊。 如果應用程式只使用 .Client
專案中註冊的 HttpClient 服務執行,如新增 HttpClient
服務一節所述,則執行應用程式會導致執行階段錯誤:
InvalidOperationException:無法為類型為 '...{COMPONENT}' 的屬性 'Http' 提供值。 沒有類型為 'System.Net.Http.HttpClient' 的已註冊服務。
使用下列其中一個方法:
將 HttpClient 服務新增至伺服器專案,在 SSR 期間提供 HttpClient。 在伺服器專案的
Program
檔案使用下列服務註冊:builder.Services.AddHttpClient();
HttpClient 服務由共用架構提供,因此不需要應用程式專案檔中的套件參考。
範例:
BlazorWebAppCallWebApi
應用程式範例中的待辦事項清單 Web API如果呼叫 Web API 的 WebAssembly 元件不需要預先轉譯,請遵循 ASP.NET Core Blazor 轉譯模式的指導停用預先轉譯。 如果您採用這個方法,則不需要將 HttpClient 服務新增至 Blazor Web App 的主要專案,因為不會在伺服器預先解譯元件。
如需詳細資訊,請參閱用戶端服務無法在預先轉譯期間解析。
已預先轉譯資料
預先轉譯時,元件會轉譯兩次:先以靜態方式轉譯,然後以互動方式轉譯。 狀態不會自動從預先轉譯的元件流向互動式元件。 如果元件執行非同步初始化作業,並在初始化期間轉譯不同狀態的不同內容,例如「載入中...」進度指示器,則元件轉譯兩次時,您可能會看到閃爍。
使用 Persistent Component State API (如 BlazorWebAppCallWebApi
和 BlazorWebAppCallWebApi_Weather
應用程式範例 所示) 流通預先轉譯的狀態,即可解決這個問題。 元件以互動方式轉譯時,可以使用相同的狀態以相同的方式轉譯。 不過,API 目前無法與增強型瀏覽搭配使用,但是在頁面 (data-enhanced-nav=false
) 連結停用增強型瀏覽即可解決這個問題。 如需詳細資訊,請參閱以下資源:
新增 HttpClient
服務
本節的指導適用於用戶端案例。
用戶端元件會使用預先設定的 HttpClient 服務來呼叫 Web API,其著重於將要求傳回來源伺服器。 其他 Web API 的其他 HttpClient 服務組態可以在開發人員程式碼中建立。 要求是使用 Blazor JSON 協助程式或搭配 HttpRequestMessage所撰寫。 要求可以包含擷取 API 選項組態。
唯有針對應用程式中單一 HttpClient 執行個體呼叫單一 Web API 時,本節的設定範例才有用。 應用程式必須呼叫多個 Web API 時,每個 API 都有自己的基底位址 (Base Address) 和設定,您可以採用本文稍後會說明的下列方法:
- 有
IHttpClientFactory
的具名HttpClient
:每個 Web API 都會獲得唯一的名稱。 應用程式程式碼或 Razor 元件呼叫 Web API 時,會使用具名 HttpClient 執行個體呼叫。 - 具類型的
HttpClient
:每個 Web API 都有類型。 應用程式程式碼或 Razor 元件呼叫 Web API 時,會使用具類型的 HttpClient 執行個體呼叫。
在 Program
檔案中,如果尚未從用來建立應用程式的 Blazor 專案範本新增 HttpClient 服務:
builder.Services.AddScoped(sp =>
new HttpClient
{
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
});
上述範例會使用 builder.HostEnvironment.BaseAddress
(IWebAssemblyHostEnvironment.BaseAddress) 設定基底位址 (Base Address),其會取得應用程式的基底位址 (Base Address),而且通常衍生自主頁面中 <base>
href
標籤的值。
使用用戶端本身基底位址 (Base Address) 最常見的使用案例如下:
- Blazor Web App (.NET 8 或更新版本) 的用戶端專案 (
.Client
) 會從 WebAssembly 元件,或是從在 WebAssembly 用戶端執行的程式碼,向伺服器應用程式中的 API 進行 Web API 呼叫。 - 裝載 Blazor WebAssembly 應用程式的用戶端專案 (Client) 會向伺服器專案 (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 是使用瀏覽器的提取 API 來實作,並受限於其限制,包括強制執行相同原始來源原則,本文稍後會在跨原始來源資源共用 (CORS) 一節中討論。
用戶端的基底位址會設定為原始伺服器的位址。 使用 @inject
指示詞將 HttpClient 執行個體插入元件:
@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 會將 POST 要求傳送至指定的 URI,其中要求本文中包含序列化為 JSON 的值。
在下列元件程式碼中,newItemName
是由元件的繫結元素所提供。 選取 <button>
元素會觸發 AddItem
方法。
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 要求。
在下列元件程式碼中,Name
和 IsCompleted
的值 editItem
是由元件的繫結元素所提供。 當項目在 UI 的另一個部分選取 (未顯示) 且呼叫 EditItem
時,就會設定項目的 Id
。 選取 <button>
元素會觸發 SaveItem
方法。 下列範例不會針對簡潔性顯示載入 todoItems
。 如需載入項目的範例,請參閱 從 JSON 獲取(GetFromJsonAsync
) 一節。
await Http.PutAsJsonAsync($"todoitems/{editItem.Id}", editItem);
PutAsJsonAsync 會傳回 HttpResponseMessage。 若要從回應訊息還原序列化 JSON 內容,請使用 ReadFromJsonAsync 擴充方法。 下列範例會以陣列的形式讀取 JSON 天氣資料:
var content = await response.Content.ReadFromJsonAsync<WeatherForecast[]>() ??
Array.Empty<WeatherForecast>();
修補檔為 JSON(PatchAsJsonAsync
)
PatchAsJsonAsync 傳送具有 JSON 編碼內容的 HTTP 修補檔要求。
注意
如需詳細資訊,請參閱 ASP.NET Core Web API 中的 JsonPatch。
在下列範例中, PatchAsJsonAsync 會以具有轉義引號的純文字字串形式接收 JSON 修補檔文件:
await Http.PatchAsJsonAsync(
$"todoitems/{id}",
"[{\"operationType\":2,\"path\":\"/IsComplete\",\"op\":\"replace\",\"value\":true}]");
PatchAsJsonAsync 會傳回 HttpResponseMessage。 若要從回應訊息還原序列化 JSON 內容,請使用 ReadFromJsonAsync 擴充方法。 下列範例會以陣列的形式讀取 JSON 待辦事項資料。 如果這個方法沒有傳回事項資料,則會建立空陣列,因此 content
在陳述式執行之後不會是 null:
var response = await Http.PatchAsJsonAsync(...);
var content = await response.Content.ReadFromJsonAsync<TodoItem[]>() ??
Array.Empty<TodoItem>();
未編碼的修補檔文件會以縮排、間距和非逸出引號編排,顯示為下列 JSON:
[
{
"operationType": 2,
"path": "/IsComplete",
"op": "replace",
"value": true
}
]
為了簡化在發出修補檔要求的應用程式中建立修補檔文件的程序,應用程式可以使用 .NET JSON 修補檔支援,如下列指導所示。
安裝 Microsoft.AspNetCore.JsonPatch
NuGet 套件,並使用套件的 API 功能來撰寫 PATCH 要求的 JsonPatchDocument。
注意
如需將套件新增至 .NET 應用程式的指引,請參閱在套件取用工作流程 (NuGet 文件) 的安裝及管理套件底下的文章。 在 NuGet.org 確認正確的套件版本。
將 System.Text.Json、System.Text.Json.Serialization 和 Microsoft.AspNetCore.JsonPatch 命名空間的 @using
指示詞,新增至 Razor 元件頂端:
@using System.Text.Json
@using System.Text.Json.Serialization
@using Microsoft.AspNetCore.JsonPatch
使用 Replace 方法撰寫 TodoItem
的 JsonPatchDocument,並將 IsComplete
設定為 true
:
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。 或者,您可以使用下列步驟,以最小 API 的形式實作 PATCH 要求處理。
將 Microsoft.AspNetCore.Mvc.NewtonsoftJson
NuGet 套件的套件參考新增至 Web API 應用程式。
注意
不需要將 Microsoft.AspNetCore.JsonPatch
套件的套件參考新增至應用程式,因為 Microsoft.AspNetCore.Mvc.NewtonsoftJson
套件的參考會自動轉移為新增 Microsoft.AspNetCore.JsonPatch
的套件參考。
在 Program
檔案新增 Microsoft.AspNetCore.JsonPatch 命名空間的 @using
指示詞:
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}");
以 IHttpClientFactory
命名 HttpClient
支援具名 HttpClient 的 IHttpClientFactory 服務和組態。
注意
使用 IHttpClientFactory 中具名 HttpClient 的替代方法是使用具型別的 HttpClient。 如需詳細資訊,請參閱具型別 HttpClient
一節。
將 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 的基底位址 (Base Address) 取代,如下所述。
上述用戶端範例會使用 builder.HostEnvironment.BaseAddress
(IWebAssemblyHostEnvironment.BaseAddress) 設定基底位址 (Base Address),藉此取得應用程式的基底位址 (Base Address),而且通常衍生自主頁面 <base>
標籤的 href
值。
使用用戶端本身基底位址 (Base Address) 最常見的使用案例如下:
- Blazor Web App 的用戶端專案 (
.Client
) 會從 WebAssembly/Auto 元件,或是從在 WebAssembly 用戶端執行的程式碼,向相同主機位址之伺服器應用程式中的 API 進行 Web API 呼叫。 - 裝載 Blazor WebAssembly 應用程式的用戶端專案 (Client) 會向伺服器專案 (Server) 進行 Web API 呼叫。
使用用戶端本身基底位址 (Base Address) 最常見的使用案例,是在裝載 Blazor WebAssembly 應用程式的用戶端專案 (Client) 中,對伺服器專案 (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 之使用是為了發出來自 Web API 於
/forecast
的 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
應用程式範例 示範在其 CallTodoWebApiCsrNamedClient
元件使用具名 HttpClient 呼叫 Web API。 如需用戶端應用程式中,採用以具名 HttpClient 呼叫 Microsoft Graph 的其他實作示範,請參閱 搭配使用圖形 API 與 ASP.NET CoreBlazor WebAssembly。
如需用戶端應用程式中,採用以具名 HttpClient 呼叫 Microsoft Graph 的實作示範,請參閱 搭配使用圖形 API 與 ASP.NET CoreBlazor WebAssembly。
具類型的 HttpClient
具型別 HttpClient 會使用一或多個應用程式的 HttpClient 執行個體 (預設或具名),從一或多個 Web API 端點傳回資料。
注意
使用具型別 HttpClient 的替代方法是使用 IHttpClientFactory 中具名的 HttpClient。 如需詳細資訊,請參閱具名的 HttpClient
與 IHttpClientFactory
一節。
將 Microsoft.Extensions.Http
NuGet 套件新增至應用程式。
注意
如需將套件新增至 .NET 應用程式的指引,請參閱在套件取用工作流程 (NuGet 文件) 的安裝及管理套件底下的文章。 在 NuGet.org 確認正確的套件版本。
以下範例發出來自 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 Address),藉以取得用戶端應用程式的基底位址 (Base Address),而且通常衍生自主頁面 <base>
標籤的 href
值。
使用用戶端本身基底位址 (Base Address) 最常見的使用案例如下:
- Blazor Web App 的用戶端專案 (
.Client
) 會從 WebAssembly/Auto 元件,或是從在 WebAssembly 用戶端執行的程式碼,向相同主機位址之伺服器應用程式中的 API 進行 Web API 呼叫。 - 裝載 Blazor WebAssembly 應用程式的用戶端專案 (Client) 會向伺服器專案 (Server) 進行 Web API 呼叫。
使用用戶端本身基底位址 (Base Address) 最常見的使用案例,是在裝載 Blazor WebAssembly 應用程式的用戶端專案 (Client) 中,對伺服器專案 (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 用於 JSON 天氣預報資料的 GET 要求。
@inject ForecastHttpClient Http
...
@code {
private Forecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
forecasts = await Http.GetForecastAsync();
}
}
BlazorWebAppCallWebApi
應用程式範例 示範在其 CallTodoWebApiCsrTypedClient
元件使用具類型 HttpClient 呼叫 Web API。 請注意,元件透過預先轉譯採用用戶端轉譯 (CSR) (InteractiveWebAssembly
轉譯模式),因此具類型的用戶端服務註冊會同時出現在伺服器專案和 .Client
專案的 Program
檔案中。
Cookie型要求認證
本節的指導適用於採用驗證的用戶端案例cookie。
針對被視為比持有人權杖驗證更安全的 cookie型驗證,可以透過預先設定之 HttpClient 上的 DelegatingHandler 呼叫 AddHttpMessageHandler,隨著每個 Web API 要求傳送 cookie 認證。 處理常式會使用 BrowserRequestCredentials.Include來設定 SetBrowserRequestCredentials ,建議瀏覽器隨每個要求傳送認證,例如 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);
}
}
CookieHandler
會在 Program
檔案中註冊:
builder.Services.AddTransient<CookieHandler>();
訊息處理常式會新增至需要 cookie 驗證的任何預先設定 HttpClient:
builder.Services.AddHttpClient(...)
.AddHttpMessageHandler<CookieHandler>();
撰寫 HttpRequestMessage 時,請直接設定瀏覽器要求認證和標頭:
var requestMessage = new HttpRequestMessage() { ... };
requestMessage.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
requestMessage.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()
{
var requestMessage = 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))
{
requestMessage.Headers.Authorization =
new AuthenticationHeaderValue("Bearer", token.Value);
requestMessage.Content.Headers.TryAddWithoutValidation(
"x-custom-header", "value");
var response = await Http.SendAsync(requestMessage);
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 設定基礎特定要求的擷取 API 選項。 使用泛型 SetBrowserRequestOption 擴充方法來設定其他選項。 Blazor 和基礎擷取 API 不會直接新增或修改要求標頭。 如需瀏覽器、與標頭互動方式這類使用者代理程式詳細資訊,請參閱外部使用者代理程式文件集和其他 Web 資源。
HTTP 回應通常會經過緩衝處理,以支援回應內容上的同步讀取。 若要啟用回應串流支援,請針對 SetBrowserResponseStreamingEnabled 要求使用擴充方法。
若要在跨原始來源要求中包含認證,請使用 SetBrowserRequestCredentials 擴充方法:
requestMessage.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
如需 Fetch API 選項的詳細資訊,請參閱 MDN Web 文件:WindowOrWorkerGlobalScope.fetch():參數。
處理錯誤
在開發人員程式碼中發生 Web API 回應錯誤時處理錯誤。 例如, GetFromJsonAsync 使用 application/json
的 Content-Type
預期來自 Web API 的 JSON 回應。 如果回應不是 JSON 格式,則內容驗證會擲回 NotSupportedException。
在下列範例中,天氣預報資料要求的 URI 端點拼錯。 URI 應為 WeatherForecast
,但在呼叫中顯示為 WeatherForcast
,其中遺漏 Forecast
中的字母 e
。
GetFromJsonAsync 呼叫預期會傳回 JSON,但 Web API 會使用 text/html
的 Content-Type
,針對未處理的例外狀況傳回 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;
}
}
}
注意
上述範例僅供示範之用。 即使端點不存在或伺服器上發生未處理的例外狀況,Web API 仍可設定為傳回 JSON。
如需詳細資訊,請參閱處理 ASP.NET Core Blazor 應用程式中的錯誤。
跨來源資源共用 (CORS)
瀏覽器安全性會限制網頁向提供網頁的不同網域提出要求。 這項限制稱為相同來源原則。 相同來源原則會限制 (但不會防止) 惡意網站從另一個網站讀取敏感性資料。 若要向具有不同來源的端點提出要求,端點必須啟用跨原始來源資源共用 (CORS)。
如需伺服器端 CORS 詳細資訊,請參閱在 ASP.NET Core 中啟用跨原始來源要求 (CORS)。 本文的範例不會直接與 Razor 元件案例相關,但本文適用於學習一般 CORS 概念。
如需用戶端 CORS 要求的資訊,請參閱 ASP.NET Core Blazor WebAssembly 其他安全性案例。
Antiforgery 支援
若要將防偽支援新增至 HTTP 要求,請插入 AntiforgeryStateProvider
,並將 RequestToken
新增至標頭集合做為 RequestVerificationToken
:
@inject AntiforgeryStateProvider Antiforgery
private async Task OnSubmit()
{
var antiforgery = Antiforgery.GetAntiforgeryToken();
var request = new HttpRequestMessage(HttpMethod.Post, "action");
request.Headers.Add("RequestVerificationToken", antiforgery.RequestToken);
var response = await client.SendAsync(request);
...
}
如需詳細資訊,請參閱 ASP.NET Core Blazor 驗證和授權。
測試 Web API 存取的 Blazor 架構元件範例
有各種公用網路工具可用於直接測試 Web API 後端應用程式,例如 Firefox Browser Developer。 Blazor 架構的參考來源包含可用於測試的 HttpClient 測試資產:
dotnet/aspnetcore
GitHub 存放庫中的 HttpClientTest
資產
注意
.NET 參考來源的文件連結通常會載入存放庫的預設分支,這表示下一版 .NET 的目前開發。 若要選取特定版本的標籤,請使用 [切換分支或標籤] 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤。
其他資源
一般
- W3C 的跨原始來源資源共用 (CORS) \(英文\)
- 在 ASP.NET Core 中啟用跨原始來源要求(CORS):雖然內容適用於 ASP.NET Core 應用程式,而非 Razor 元件,但本文涵蓋一般 CORS 概念。
降低過度發佈攻擊的風險
Web API 可能容易受到「過度發佈」攻擊,其也稱為「大量指派」攻擊。 當惡意使用者向伺服器發出 HTML 表單 POST 要求,該伺服器處理不屬於所轉譯表單的屬性的資料且開發人員不希望允許使用者修改該屬性時,就會發生過度發佈攻擊。 「過度發佈」一詞的字面意思是惡意使用者已過度發佈表單。
如需降低過度發佈攻擊風險的指引,請參閱 教學課程:使用 ASP.NET Core 建立 Web API。
伺服器端
- 伺服器端 ASP.NET Core Blazor 其他安全性案例:包含使用 HttpClient 進行安全 Web API 要求的涵蓋範圍。
- 在 ASP.NET Core 中使用 IHttpClientFactory 發出 HTTP 要求
- 在 ASP.NET Core 中強制執行 HTTPS
- Kestrel HTTPS 端點組態
用戶端
- ASP.NET Core Blazor WebAssembly 其他安全性案例:包含使用 HttpClient 進行安全 Web API 要求的涵蓋範圍。
- 搭配使用圖形 API 與 ASP.NET Core Blazor WebAssembly
- Fetch API