--- title: Call a web API from ASP.NET Core Blazor WebAssembly author: guardrex description: Learn how to call a web API from a Blazor WebAssembly app using JSON helpers, including making cross-origin resource sharing (CORS) requests. monikerRange: '>= aspnetcore-3.1' ms.author: riande ms.custom: mvc ms.date: 06/24/2020 no-loc: [cookie, Cookie, Blazor, "Blazor Server", "Blazor WebAssembly", "Identity", "Let's Encrypt", Razor, SignalR] uid: blazor/call-web-api --- # Call a web API from ASP.NET Core Blazor By [Luke Latham](https://github.com/guardrex), [Daniel Roth](https://github.com/danroth27), and [Juan De la Cruz](https://github.com/juandelacruz23) > [!NOTE] > This topic applies to Blazor WebAssembly. [Blazor Server](xref:blazor/hosting-models#blazor-server) apps call web APIs using instances, typically created using . For guidance that applies to Blazor Server, see . [Blazor WebAssembly](xref:blazor/hosting-models#blazor-webassembly) apps call web APIs using a preconfigured service. Compose requests, which can include JavaScript [Fetch API](https://developer.mozilla.org/docs/Web/API/Fetch_API) options, using Blazor JSON helpers or with . The service in Blazor WebAssembly apps is focused on making requests back to the server of origin. The guidance in this topic only pertains to Blazor WebAssembly apps. [View or download sample code](https://github.com/dotnet/AspNetCore.Docs/tree/master/aspnetcore/blazor/common/samples/) ([how to download](xref:index#how-to-download-a-sample)): Select the `BlazorWebAssemblySample` app. See the following components in the `BlazorWebAssemblySample` sample app: * Call Web API (`Pages/CallWebAPI.razor`) * HTTP Request Tester (`Components/HTTPRequestTester.razor`) ## Packages Reference the [`System.Net.Http.Json`](https://www.nuget.org/packages/System.Net.Http.Json) NuGet package in the project file. ## Add the HttpClient service In `Program.Main`, add an service if it doesn't already exist: ```csharp builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); ``` ## HttpClient and JSON helpers In a Blazor WebAssembly app, [`HttpClient`](xref:fundamentals/http-requests) is available as a preconfigured service for making requests back to the origin server. A Blazor Server app doesn't include an service by default. Provide an to the app using the [`HttpClient` factory infrastructure](xref:fundamentals/http-requests). and JSON helpers are also used to call third-party web API endpoints. is implemented using the browser [Fetch API](https://developer.mozilla.org/docs/Web/API/Fetch_API) and is subject to its limitations, including enforcement of the same origin policy. The client's base address is set to the originating server's address. Inject an instance using the [`@inject`](xref:mvc/views/razor#inject) directive: ```razor @using System.Net.Http @inject HttpClient Http ``` In the following examples, a Todo web API processes create, read, update, and delete (CRUD) operations. The examples are based on a `TodoItem` class that stores the: * ID (`Id`, `long`): Unique ID of the item. * Name (`Name`, `string`): Name of the item. * Status (`IsComplete`, `bool`): Indication if the Todo item is finished. ```csharp private class TodoItem { public long Id { get; set; } public string Name { get; set; } public bool IsComplete { get; set; } } ``` JSON helper methods send requests to a URI (a web API in the following examples) and process the response: * : Sends an HTTP GET request and parses the JSON response body to create an object. In the following code, the `todoItems` are displayed by the component. The `GetTodoItems` method is triggered when the component is finished rendering ([`OnInitializedAsync`](xref:blazor/components/lifecycle#component-initialization-methods)). See the sample app for a complete example. ```razor @using System.Net.Http @inject HttpClient Http @code { private TodoItem[] todoItems; protected override async Task OnInitializedAsync() => todoItems = await Http.GetFromJsonAsync("api/TodoItems"); } ``` * : Sends an HTTP POST request, including JSON-encoded content, and parses the JSON response body to create an object. In the following code, `newItemName` is provided by a bound element of the component. The `AddItem` method is triggered by selecting a ` @code { private string newItemName; private async Task AddItem() { var addItem = new TodoItem { Name = newItemName, IsComplete = false }; await Http.PostAsJsonAsync("api/TodoItems", addItem); } } ``` Calls to return an . To deserialize the JSON content from the response message, use the `ReadFromJsonAsync` extension method: ```csharp var content = response.Content.ReadFromJsonAsync(); ``` * : Sends an HTTP PUT request, including JSON-encoded content. In the following code, `editItem` values for `Name` and `IsCompleted` are provided by bound elements of the component. The item's `Id` is set when the item is selected in another part of the UI and `EditItem` is called. The `SaveItem` method is triggered by selecting the Save ` @code { private TodoItem editItem = new TodoItem(); private void EditItem(long id) { editItem = todoItems.Single(i => i.Id == id); } private async Task SaveItem() => await Http.PutAsJsonAsync($"api/TodoItems/{editItem.Id}, editItem); } ``` Calls to return an . To deserialize the JSON content from the response message, use the extension method: ```csharp var content = response.Content.ReadFromJsonAsync(); ``` includes additional extension methods for sending HTTP requests and receiving HTTP responses. is used to send an HTTP DELETE request to a web API. In the following code, the Delete ` @code { private long id; private async Task DeleteItem() => await Http.DeleteAsync($"api/TodoItems/{id}"); } ``` ## Named HttpClient with IHttpClientFactory services and the configuration of a named are supported. Reference the [`Microsoft.Extensions.Http`](https://www.nuget.org/packages/Microsoft.Extensions.Http) NuGet package in the project file. `Program.Main` (`Program.cs`): ```csharp builder.Services.AddHttpClient("ServerAPI", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)); ``` `FetchData` component (`Pages/FetchData.razor`): ```razor @inject IHttpClientFactory ClientFactory ... @code { private WeatherForecast[] forecasts; protected override async Task OnInitializedAsync() { var client = ClientFactory.CreateClient("ServerAPI"); forecasts = await client.GetFromJsonAsync( "WeatherForecast"); } } ``` ## Typed HttpClient Typed uses one or more of the app's instances, default or named, to return data from one or more web API endpoints. `WeatherForecastClient.cs`: ```csharp using System.Net.Http; using System.Net.Http.Json; using System.Threading.Tasks; public class WeatherForecastClient { private readonly HttpClient client; public WeatherForecastClient(HttpClient client) { this.client = client; } public async Task GetForecastAsync() { var forecasts = new WeatherForecast[0]; try { forecasts = await client.GetFromJsonAsync( "WeatherForecast"); } catch { ... } return forecasts; } } ``` `Program.Main` (`Program.cs`): ```csharp builder.Services.AddHttpClient(client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)); ``` Components inject the typed to call the web API. `FetchData` component (`Pages/FetchData.razor`): ```razor @inject WeatherForecastClient Client ... @code { private WeatherForecast[] forecasts; protected override async Task OnInitializedAsync() { forecasts = await Client.GetForecastAsync(); } } ``` ## Handle errors When errors occur while interacting with a web API, they can be handled by developer code. For example, expects a JSON response from the server API with a `Content-Type` of `application/json`. If the response isn't in JSON format, content validation throws a . In the following example, the URI endpoint for the weather forecast data request is misspelled. The URI should be to `WeatherForecast` but appears in the call as `WeatherForcast` (missing "e"). The call expects JSON to be returned, but the server returns HTML for an unhandled exception on the server with a `Content-Type` of `text/html`. The unhandled exception occurs on the server because the path isn't found and middleware can't serve a page or view for the request. In on the client, is thrown when the response content is validated as non-JSON. The exception is caught in the `catch` block, where custom logic could log the error or present a friendly error message to the user: ```csharp protected override async Task OnInitializedAsync() { try { forecasts = await Http.GetFromJsonAsync( "WeatherForcast"); } catch (NotSupportedException exception) { ... } } ``` > [!NOTE] > The preceding example is for demonstration purposes. A web API server app can be configured to return JSON even when an endpoint doesn't exist or an unhandled exception on the server occurs. For more information, see . ## Cross-origin resource sharing (CORS) Browser security prevents a webpage from making requests to a different domain than the one that served the webpage. This restriction is called the *same-origin policy*. The same-origin policy prevents a malicious site from reading sensitive data from another site. To make requests from the browser to an endpoint with a different origin, the *endpoint* must enable [cross-origin resource sharing (CORS)](https://www.w3.org/TR/cors/). The [Blazor WebAssembly sample app (BlazorWebAssemblySample)](https://github.com/dotnet/AspNetCore.Docs/tree/master/aspnetcore/blazor/common/samples/) demonstrates the use of CORS in the Call Web API component (`Pages/CallWebAPI.razor`). For more information on CORS with secure requests in Blazor apps, see . For general information on CORS with ASP.NET Core apps, see . ## Additional resources * : Includes coverage on using to make secure web API requests. * * * [Kestrel HTTPS endpoint configuration](xref:fundamentals/servers/kestrel#endpoint-configuration) * [Cross Origin Resource Sharing (CORS) at W3C](https://www.w3.org/TR/cors/)