Call a web API from ASP.NET Core Blazor

By Luke Latham, Daniel Roth, and Juan De la Cruz

Important

Blazor WebAssembly in preview

Blazor Server is supported in ASP.NET Core 3.0. Blazor WebAssembly is in preview for ASP.NET Core 3.1.

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 HttpRequestMessage.

Blazor Server apps call web APIs using HttpClient instances typically created using IHttpClientFactory. For more information, see Make HTTP requests using IHttpClientFactory in ASP.NET Core.

View or download sample code (how to download) – 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 experimental Microsoft.AspNetCore.Blazor.HttpClient NuGet package in the project file. Microsoft.AspNetCore.Blazor.HttpClient is based on HttpClient and System.Text.Json.

To use a stable API, use the Microsoft.AspNet.WebApi.Client package, which uses Newtonsoft.Json/Json.NET. Using the stable API in Microsoft.AspNet.WebApi.Client doesn't provide the JSON helpers described in this topic, which are unique to the experimental Microsoft.AspNetCore.Blazor.HttpClient package.

HttpClient and JSON helpers

In a Blazor WebAssembly app, HttpClient is available as a preconfigured service for making requests back to the origin server.

A Blazor Server app doesn't include an HttpClient service by default. Provide an HttpClient to the app using the HttpClient factory infrastructure.

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. The GetTodoItems 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. The AddItem 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 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 <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);
    }
    

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 Blazor WebAssembly sample app (BlazorWebAssemblySample) 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 Enable Cross-Origin Requests (CORS) in ASP.NET Core.

HttpClient and HttpRequestMessage with Fetch API request options

When running on WebAssembly in a Blazor WebAssembly app, use HttpClient and HttpRequestMessage to customize requests. For example, you can specify the request URI, HTTP method, and any desired request headers.

@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");

        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 and Authorization headers. To allow a custom header (for example, x-custom-header), list the header when calling WithHeaders.
  • Credentials set by client-side JavaScript code (credentials property set to include).
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 Enable Cross-Origin Requests (CORS) in ASP.NET Core and the sample app's HTTP Request Tester component (Components/HTTPRequestTester.razor).

Additional resources