從 ASP.NET Core 呼叫 Web API Blazor

注意

這不是這篇文章的最新版本。 如需目前版本,請參閱本文的 .NET 8 版本

重要

這些發行前產品的相關資訊在產品正式發行前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。

如需目前版本,請參閱本文的 .NET 8 版本

本文說明如何從 Blazor 應用程式呼叫 Web API。

套件

System.Net.Http.Json 套件提供適用於 System.Net.Http.HttpClientSystem.Net.Http.HttpContent 的擴充方法,這些方法會使用 System.Text.Json 來執行自動序列化及還原序列化。 System.Net.Http.Json 套件是由 .NET 共用架構所提供,且不需要將套件參考新增至應用程式。

範例應用程式

請參閱 dotnet/blazor-samples GitHub 存放庫中的應用程式範例。

BlazorWebAppCallWebApi

從 Blazor Web 應用程式呼叫外部 (不在 Blazor Web App) 待辦事項清單 Web API:

  • Backend:Web API 應用程式,可根據 最小 API 維護待辦事項清單。 Web API 應用程式是與 Blazor Web 應用程式不同的應用程式,可能裝載於不同的伺服器。
  • BlazorApp/BlazorApp.Client:這個Blazor Web 應用程式使用 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 應用程式) 電影清單 API,其中 API 位於 Blazor Web 應用程式的伺服器專案:

  • BlazorApp:維護電影清單的 Blazor Web 應用程式:
    • 作業在伺服器應用程式內的電影清單執行時,使用的是一般 API 呼叫。
    • WEB 型用戶端進行 API 呼叫時,Web API 會根據最小 API 用於電影清單作業。
  • BlazorApp.Client:Blazor Web 應用程式的客戶端專案,其中包含用於電影清單使用者管理的互動式 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)
    {
        return 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)
    {
        return 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 應用程式,該程式會維護伺服器專案中的 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 應用程式

Blazor Web 應用程式外部 Web API

本節適用於 Blazor Web 應用程式,該程式會呼叫個別 (外部) 專案維護的 Web API (可能裝載於不同的伺服器)。

Blazor Web 應用程式通常會預先轉譯用戶端 WebAssembly 元件,而 Auto 元件則是在靜態或互動式伺服器端轉譯 (SSR) 期間於伺服器轉譯。 HttpClient 服務預設不會在 Blazor Web 應用程式的主要項目註冊。 如果應用程式只使用 .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 應用程式的主要專案,因為不會在伺服器預先解譯元件。

如需詳細資訊,請參閱用戶端服務無法在預先轉譯期間解析

已預先轉譯資料

預先轉譯時,元件會轉譯兩次:先以靜態方式轉譯,然後以互動方式轉譯。 狀態不會自動從預先轉譯的元件流向互動式元件。 如果元件執行非同步初始化作業,並在初始化期間轉譯不同狀態的不同內容,例如「載入中...」進度指示器,則元件轉譯兩次時,您可能會看到閃爍。

使用 Persistent Component State API (如 BlazorWebAppCallWebApiBlazorWebAppCallWebApi_Weather應用程式範例 所示) 流通預先轉譯的狀態,即可解決這個問題。 元件以互動方式轉譯時,可以使用相同的狀態以相同的方式轉譯。 不過,API 目前無法與增強型瀏覽搭配使用,但是在頁面 (data-enhanced-nav=false) 連結停用增強型瀏覽即可解決這個問題。 如需詳細資訊,請參閱以下資源:

新增 HttpClient 服務

本節的指導適用於用戶端案例。

用戶端元件會使用預先設定的 HttpClient 服務來呼叫 Web API,其著重於將要求傳回來源伺服器。 其他 Web API 的其他 HttpClient 服務組態可以在開發人員程式碼中建立。 要求是使用 BlazorJSON 協助程式或搭配 HttpRequestMessage 所撰寫。 要求可以包含擷取 API 選項組態。

唯有針對應用程式中單一 HttpClient 執行個體呼叫單一 Web API 時,本節的設定範例才有用。 應用程式必須呼叫多個 Web API 時,每個 API 都有自己的基底位址 (Base Address) 和設定,您可以採用本文稍後會說明的下列方法:

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 應用程式 (.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,包括 GetFromJsonAsyncPutAsJsonAsyncPostAsJsonAsync

@using System.Net.Http.Json

下列各節說明 JSON 協助程式:

System.Net.Http 包含傳送 HTTP 要求及接收 HTTP 回應的其他方法,例如傳送 DELETE 要求。 如需詳細資訊,請參閱 DELETE 和其他擴充方法一節。

GET from JSON (GetFromJsonAsync)

GetFromJsonAsync 會傳送 HTTP GET 要求,並剖析 JSON 回應本文以建立物件。

在下列元件程式碼中,元件會顯示 todoItems。 當元件完成初始化時,會呼叫 GetFromJsonAsync (OnInitializedAsync)。

todoItems = await Http.GetFromJsonAsync<TodoItem[]>("todoitems");

POST as 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>();

PUT as JSON (PutAsJsonAsync)

PutAsJsonAsync 傳送具有 JSON 編碼內容的 HTTP PUT 要求。

在下列元件程式碼中,NameIsCompleted 的值 editItem 是由元件的繫結元素所提供。 當項目在 UI 的另一個部分選取 (未顯示) 且呼叫 EditItem 時,就會設定項目的 Id。 選取 <button> 元素會觸發 SaveItem 方法。 下列範例不會針對簡潔性顯示載入 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 as JSON (PatchAsJsonAsync)

PatchAsJsonAsync 傳送具有 JSON 編碼內容的 HTTP PATCH 要求。

注意

如需詳細資訊,請參閱 ASP.NET Core Web API 中的 JsonPatch

在下列範例中,PatchAsJsonAsync 會以純文字字串形式接收有逸出引號的 JSON PATCH 文件:

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>();

未編碼的 PATCH 文件會以縮排、間距和非逸出引號編排,顯示為下列 JSON:

[
  {
    "operationType": 2,
    "path": "/IsComplete",
    "op": "replace",
    "value": true
  }
]

為了簡化在發出 PATCH 要求的應用程式中建立 PATCH 文件的程序,應用程式可以使用 .NET JSON PATCH 支援,如下列指引所示。

安裝 Microsoft.AspNetCore.JsonPatch NuGet 套件,並使用套件的 API 功能來撰寫 PATCH 要求的 JsonPatchDocument

注意

如需將套件新增至 .NET 應用程式的指引,請參閱在套件取用工作流程 (NuGet 文件)安裝及管理套件底下的文章。 在 NuGet.org 確認正確的套件版本。

System.Text.JsonSystem.Text.Json.SerializationMicrosoft.AspNetCore.JsonPatch 命名空間的 @using 指示詞,新增至 Razor 元件頂端:

@using System.Text.Json
@using System.Text.Json.Serialization
@using Microsoft.AspNetCore.JsonPatch

使用 Replace 方法撰寫 TodoItemJsonPatchDocument,並將 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 並不會影響處理 PATCH 要求,且通常不會在 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

支援具名 HttpClientIHttpClientFactory 服務和組態。

注意

使用 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 應用程式預先轉譯的用戶端元件使用,則上述服務註冊應該會同時出現在伺服器專案和 .Client 專案。 在伺服器上,builder.HostEnvironment.BaseAddress 會由 Web API 的基底位址 (Base Address) 取代,如下所述。

上述用戶端範例會使用 builder.HostEnvironment.BaseAddress (IWebAssemblyHostEnvironment.BaseAddress) 設定基底位址 (Base Address),藉此取得應用程式的基底位址 (Base Address),而且通常衍生自主頁面 <base> 標籤的 href 值。

使用用戶端本身基底位址 (Base Address) 最常見的使用案例如下:

  • Blazor Web 應用程式的用戶端專案 (.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));

在下列元件程式碼中:

@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。 如需詳細資訊,請參閱具名的 HttpClientIHttpClientFactory 一節。

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()
    {
        return await http.GetFromJsonAsync<Forecast[]>("forecast") ?? [];
    }
}

在用戶端專案的 Program 檔案:

builder.Services.AddHttpClient<ForecastHttpClient>(client => 
    client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));

如果具類型用戶端是由 Blazor Web 應用程式預先轉譯的用戶端元件使用,則上述服務註冊應該會同時出現在伺服器專案和 .Client 專案。 在伺服器上,builder.HostEnvironment.BaseAddress 會由 Web API 的基底位址 (Base Address) 取代,如下所述。

上述範例會使用 builder.HostEnvironment.BaseAddress (IWebAssemblyHostEnvironment.BaseAddress) 設定基底位址 (Base Address),藉以取得用戶端應用程式的基底位址 (Base Address),而且通常衍生自主頁面 <base> 標籤的 href 值。

使用用戶端本身基底位址 (Base Address) 最常見的使用案例如下:

  • Blazor Web 應用程式的用戶端專案 (.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型驗證,可以透過預先設定之 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"]);

HttpClientHttpRequestMessage 具有 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 預期來自 Web API 的 JSON 回應,且 application/jsonContent-Type。 如果回應不是 JSON 格式,則內容驗證會擲回 NotSupportedException

在下列範例中,天氣預報資料要求的 URI 端點拼錯。 URI 應為 WeatherForecast,但在呼叫中顯示為 WeatherForcast,其中遺漏 Forecast 中的字母 e

GetFromJsonAsync 呼叫預期會傳回 JSON,但 Web API 會針對未處理的例外狀況傳回 HTML,且 text/htmlContent-Type。 之所以發生未處理的例外狀況是因為找不到 /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 &#8451;
                @forecast.TemperatureF &#8457;
            </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/aspnetcoreGitHub 存放庫中的 HttpClientTest 資產

注意

.NET 參考來源的文件連結通常會載入存放庫的預設分支,這表示下一版 .NET 的目前開發。 若要選取特定版本的標籤,請使用 [切換分支或標籤] 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤

其他資源

一般

伺服器端

用戶端