10 KiB
title | author | description | monikerRange | ms.author | ms.custom | ms.date | no-loc | uid | |
---|---|---|---|---|---|---|---|---|---|
Call a web API from ASP.NET Core Blazor | guardrex | Learn how to call a web API from a Blazor app using JSON helpers, including making cross-origin resource sharing (CORS) requests. | >= aspnetcore-3.0 | riande | mvc | 10/15/2019 |
|
blazor/call-web-api |
Call a web API from ASP.NET Core Blazor
By Luke Latham, Daniel Roth, and Juan De la Cruz
Blazor WebAssembly apps call web APIs using a preconfigured HttpClient
service. Compose requests, which can include JavaScript Fetch API options, using Blazor JSON helpers or with xref:System.Net.Http.HttpRequestMessage.
Blazor Server apps call web APIs using xref:System.Net.Http.HttpClient instances typically created using xref:System.Net.Http.IHttpClientFactory. For more information, see xref:fundamentals/http-requests.
View or download sample code (how to download)
For Blazor WebAssembly examples, see the following components in the sample app:
- Call Web API (Pages/CallWebAPI.razor)
- HTTP Request Tester (Components/HTTPRequestTester.razor)
HttpClient and JSON helpers
In Blazor WebAssembly apps, HttpClient is available as a preconfigured service for making requests back to the origin server. To use HttpClient
JSON helpers, add a package reference to Microsoft.AspNetCore.Blazor.HttpClient
. HttpClient
and JSON helpers are also used to call third-party web API endpoints. HttpClient
is implemented using the browser 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 HttpClient
instance using the @inject
directive:
@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.
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:
-
GetJsonAsync
– 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. TheGetTodoItems
method is triggered when the component is finished rendering (OnInitializedAsync). See the sample app for a complete example.@using System.Net.Http @inject HttpClient Http @code { private TodoItem[] _todoItems; protected override async Task OnInitializedAsync() => _todoItems = await Http.GetJsonAsync<TodoItem[]>("api/TodoItems"); }
-
PostJsonAsync
– 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. TheAddItem
method is triggered by selecting a<button>
element. See the sample app for a complete example.@using System.Net.Http @inject HttpClient Http <input @bind="_newItemName" placeholder="New Todo Item" /> <button @onclick="@AddItem">Add</button> @code { private string _newItemName; private async Task AddItem() { var addItem = new TodoItem { Name = _newItemName, IsComplete = false }; await Http.PostJsonAsync("api/TodoItems", addItem); } }
-
PutJsonAsync
– Sends an HTTP PUT request, including JSON-encoded content.In the following code,
_editItem
values forName
andIsCompleted
are provided by bound elements of the component. The item'sId
is set when the item is selected in another part of the UI andEditItem
is called. TheSaveItem
method is triggered by selecting the Save<button>
element. See the sample app for a complete example.@using System.Net.Http @inject HttpClient Http <input type="checkbox" @bind="_editItem.IsComplete" /> <input @bind="_editItem.Name" /> <button @onclick="@SaveItem">Save</button> @code { private TodoItem _editItem = new TodoItem(); private void EditItem(long id) { var editItem = _todoItems.Single(i => i.Id == id); _editItem = new TodoItem { Id = editItem.Id, Name = editItem.Name, IsComplete = editItem.IsComplete }; } private async Task SaveItem() => await Http.PutJsonAsync($"api/TodoItems/{_editItem.Id}, _editItem); }
xref:System.Net.Http includes additional extension methods for sending HTTP requests and receiving HTTP responses. HttpClient.DeleteAsync is used to send an HTTP DELETE request to a web API.
In the following code, the Delete <button>
element calls the DeleteItem
method. The bound <input>
element supplies the id
of the item to delete. See the sample app for a complete example.
@using System.Net.Http
@inject HttpClient Http
<input @bind="_id" />
<button @onclick="@DeleteItem">Delete</button>
@code {
private long _id;
private async Task DeleteItem() =>
await Http.DeleteAsync($"api/TodoItems/{_id}");
}
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).
The sample app demonstrates the use of CORS in the Call Web API component (Pages/CallWebAPI.razor).
To allow other sites to make cross-origin resource sharing (CORS) requests to your app, see xref:security/cors.
HttpClient and HttpRequestMessage with Fetch API request options
When running on WebAssembly in a Blazor WebAssembly app, use HttpClient and xref:System.Net.Http.HttpRequestMessage to customize requests. For example, you can specify the request URI, HTTP method, and any desired request headers.
Supply request options to the underlying JavaScript Fetch API using the WebAssemblyHttpMessageHandler.FetchArgs
property on the request. As shown in the following example, the credentials
property is set to any of the following values:
FetchCredentialsOption.Include
("include") – Advises the browser to send credentials (such as cookies or HTTP authentication headers) even for cross-origin requests. Only allowed when the CORS policy is configured to allow credentials.FetchCredentialsOption.Omit
("omit") – Advises the browser never to send credentials (such as cookies or HTTP auth headers).FetchCredentialsOption.SameOrigin
("same-origin") – Advises the browser to send credentials (such as cookies or HTTP auth headers) only if the target URL is on the same origin as the calling application.
@using System.Net.Http
@using System.Net.Http.Headers
@inject HttpClient Http
@code {
private async Task PostRequest()
{
Http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", "{OAUTH TOKEN}");
var requestMessage = new HttpRequestMessage()
{
Method = new HttpMethod("POST"),
RequestUri = new Uri("https://localhost:10000/api/TodoItems"),
Content =
new StringContent(
@"{""name"":""A New Todo Item"",""isComplete"":false}")
};
requestMessage.Content.Headers.ContentType =
new System.Net.Http.Headers.MediaTypeHeaderValue(
"application/json");
requestMessage.Content.Headers.TryAddWithoutValidation(
"x-custom-header", "value");
requestMessage.Properties[WebAssemblyHttpMessageHandler.FetchArgs] = new
{
credentials = FetchCredentialsOption.Include
};
var response = await Http.SendAsync(requestMessage);
var responseStatusCode = response.StatusCode;
var responseBody = await response.Content.ReadAsStringAsync();
}
}
For more information on Fetch API options, see MDN web docs: WindowOrWorkerGlobalScope.fetch():Parameters.
When sending credentials (authorization cookies/headers) on CORS requests, the Authorization
header must be allowed by the CORS policy.
The following policy includes configuration for:
- Request origins (
http://localhost:5000
,https://localhost:5001
). - Any method (verb).
Content-Type
andAuthorization
headers. To allow a custom header (for example,x-custom-header
), list the header when calling xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.WithHeaders*.- Credentials set by client-side JavaScript code (
credentials
property set toinclude
).
app.UseCors(policy =>
policy.WithOrigins("http://localhost:5000", "https://localhost:5001")
.AllowAnyMethod()
.WithHeaders(HeaderNames.ContentType, HeaderNames.Authorization, "x-custom-header")
.AllowCredentials());
For more information, see xref:security/cors and the sample app's HTTP Request Tester component (Components/HTTPRequestTester.razor).