Call a web API from ASP.NET Core Blazor

By Luke Latham and Daniel Roth

Important

Blazor WebAssembly in preview

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

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)

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. 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/todo");
    }
    
  • 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/todo", 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/todo/{_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/todo/{_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 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.

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/todo"),
            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 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