Consuming ASP.NET Core Web APIs

.NET Core Logo

Introduction

This tutorial explores various methods and best practices for consuming ASP.NET Core Web APIs from different client applications. We'll cover fundamental concepts, common scenarios, and provide practical code examples.

Web APIs are essential for modern application development, enabling communication between services and clients. Understanding how to effectively consume these APIs is crucial for building robust and scalable applications.

Client Technologies

ASP.NET Core Web APIs can be consumed by a wide range of client technologies, including:

Using the HttpClient Class

In .NET, the HttpClient class is the primary tool for making HTTP requests. It's designed to be instantiated once and reused throughout the application's lifetime for better performance and resource management.

Tip: Avoid creating a new HttpClient instance for every request. Use a single, static instance or leverage dependency injection for better performance.

public static class ApiHelper
{
    private static readonly HttpClient client = new HttpClient();

    static ApiHelper()
    {
        // Configure base address, headers, timeouts, etc.
        client.BaseAddress = new Uri("https://localhost:5001/"); // Example API base URL
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
    }

    public static async Task<string> GetAsync(string requestUri)
    {
        HttpResponseMessage response = await client.GetAsync(requestUri);
        response.EnsureSuccessStatusCode(); // Throws an exception if the status code is not a success code.
        return await response.Content.ReadAsStringAsync();
    }

    // Add methods for POST, PUT, DELETE, etc.
}
            

Making Requests

GET Requests

Used to retrieve data from the API.


public async Task<List<Product>> GetProductsAsync()
{
    string responseBody = await ApiHelper.GetAsync("api/products");
    var products = JsonSerializer.Deserialize<List<Product>>(responseBody);
    return products;
}
            

POST Requests

Used to create new resources on the API.


public async Task<HttpResponseMessage> CreateProductAsync(Product product)
{
    string jsonProduct = JsonSerializer.Serialize(product);
    var content = new StringContent(jsonProduct, System.Text.Encoding.UTF8, "application/json");

    HttpResponseMessage response = await client.PostAsync("api/products", content);
    response.EnsureSuccessStatusCode();
    return response;
}
            

PUT Requests

Used to update existing resources.


public async Task<HttpResponseMessage> UpdateProductAsync(int id, Product product)
{
    string jsonProduct = JsonSerializer.Serialize(product);
    var content = new StringContent(jsonProduct, System.Text.Encoding.UTF8, "application/json");

    HttpResponseMessage response = await client.PutAsync($"api/products/{id}", content);
    response.EnsureSuccessStatusCode();
    return response;
}
            

DELETE Requests

Used to delete resources.


public async Task<HttpResponseMessage> DeleteProductAsync(int id)
{
    HttpResponseMessage response = await client.DeleteAsync($"api/products/{id}");
    response.EnsureSuccessStatusCode();
    return response;
}
            

Handling Responses

After making a request, you'll receive an HttpResponseMessage. You can access the status code, headers, and body of the response.

The response body is typically read as a string using ReadAsStringAsync() and then deserialized into a .NET object, often using System.Text.Json or Newtonsoft.Json.

Note: Ensure your API returns JSON responses and that your client is configured to accept JSON.

Error Handling

It's crucial to handle potential errors gracefully. This includes network errors, server errors (status codes 4xx and 5xx), and issues during deserialization.

The EnsureSuccessStatusCode() method on HttpResponseMessage is a convenient way to automatically throw an exception for non-success status codes.


try
{
    var response = await client.GetAsync("api/nonexistent");
    response.EnsureSuccessStatusCode(); // This will throw if status is not 2xx
    // Process successful response
}
catch (HttpRequestException e)
{
    Console.WriteLine($"Request error: {e.Message}");
    // Handle the error appropriately (e.g., show an error message to the user)
}
catch (JsonException e)
{
    Console.WriteLine($"JSON deserialization error: {e.Message}");
    // Handle deserialization errors
}
            

Advanced Topics

For more complex scenarios, consider: