bob82
bob82

Reputation: 505

How to configure multiple HttpClient instances with different configurations in Blazor WebAssembly

I'm trying to configure multiple API urls in the Program.cs class in Blazor WASM. I'm not seeing an AddHttpClient extension like in server-side. Was wondering if anyone had an alternate solution for this?

Here's what I have so far:

var firstURI = new Uri("https://localhost:44340/");
var secondURI = new Uri("https://localhost:5001/");

void RegisterTypedClient<TClient, TImplementation>(Uri apiBaseUrl)
   where TClient : class where TImplementation : class, TClient
{
   builder.Services.AddHttpClient<TClient, TImplementation>(client =>
   {
       client.BaseAddress = apiBaseUrl;
   });
}

// HTTP services
RegisterTypedClient<IFirstService, FirstService>(firstURI);
RegisterTypedClient<ISecondService, SecondService>(secondURI);

Upvotes: 16

Views: 16549

Answers (3)

NORWEST-CONNECT
NORWEST-CONNECT

Reputation: 3

This might be heaps late. But I wanted to add that if you have many clients you want to register, you can always create a client factory extension and then add in the clients reading from appsettings.json into your programs.cs

public static class ClientFactoryExtension{
public static void AddClientAbstractFactory<THandler>(
    this IServiceCollection services, 
    string clientName, 
    string url)

    where THandler : AuthorizationMessageHandler
{
    // register handler
    services.AddTransient<THandler>();

    // register client
    services.AddHttpClient(clientName, client => client.BaseAddress = new Uri(url))
            .AddHttpMessageHandler<THandler>();

}

}

Then you can create a method that lets you register all your clients like so:

public static class ClientServices{
public static IServiceCollection AddClientServices(this IServiceCollection Services, IConfiguration Configuration)
{
    Services.AddClientAbstractFactory<Client1AuthorizationMessageHandler>(
            "client1", Configuration.GetValue<string>("client1:BaseUrl"));
    Services.AddClientAbstractFactory<Client2AuthorizationMessageHandler>(
            "client2", Configuration.GetValue<string>("client2:BaseUrl"));
    Services.AddClientAbstractFactory<Client3AuthorizationMessageHandler>(
            "client3", Configuration.GetValue<string>("client3:BaseUrl"));

    return Services;
}

}

And finally in programs.cs, you can do the following:

builder.Services.AddClientServices(builder.Configuration);

And done.

Upvotes: 0

iCollect.it Ltd
iCollect.it Ltd

Reputation: 93601

The current answer seems overly complicated.

You can simply use named HttpClients and inject the IHttpClientFactory into a page instead and create a HttpClient for a specific named configuration.

e.g. This example provides both an authorised client and an anonymous one (to access anonymous server endpoints).

in program.cs:

        builder.Services.AddHttpClient("BlazorApp.ServerAPI", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
            .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
        builder.Services.AddHttpClient("Anonymous", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));

in the razor page

@inject IHttpClientFactory clientFactory;

and use with

var httpClient = clientFactory.CreateClient("Anonymous");
var someData = await httpClient.GetFromJsonAsync<SomeData>($"api/someendpoint");

Upvotes: 4

Kuroiyatsu
Kuroiyatsu

Reputation: 676

This can be done with Blazor Client Side. First, in your client-side package, get the following nuget package: Microsoft.Extensions.Http

Then, create two classes for this example (normally you would use an interface, but a class on its own should work here. I am going to demonstrate two different base addresses being used so you know there is a difference.

   public class GoogleService
    {
        private readonly HttpClient httpClient;

        public GoogleService(HttpClient httpClient)
        {
            this.httpClient = httpClient;
        }

        public string GetBaseUrl()
        {
            return httpClient.BaseAddress.ToString();
        }
    }

And the Yahoo Service:

  public class YahooService
    {
        private readonly HttpClient httpClient;

        public YahooService(HttpClient httpClient)
        {
            this.httpClient = httpClient;
        }

        public string GetBaseUrl()
        {
            return httpClient.BaseAddress.ToString();
        }
    }

Next, in your Client Program's Program.cs, you can do something like the following:

public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);
            builder.RootComponents.Add<App>("app");

            builder.Services.AddHttpClient<GoogleService>(client =>
            {
                client.BaseAddress = new Uri("https://google.com/");
            });

            builder.Services.AddHttpClient<YahooService>(client =>
            {
                client.BaseAddress = new Uri("https://yahoo.com/");
            });

            await builder.Build().RunAsync();
        }

Next, you can inject them into your front end like so, and see that they are indeed two different injected clients:

@page "/"
@inject BlazorHttpClientTest.Client.Clients.GoogleService googleService;
@inject BlazorHttpClientTest.Client.Clients.YahooService yahooService;

<h1>Hello, world!</h1>

<label>Google Address:</label><label>@googleAddress</label>
<label>Yahoo Address:</label><label>@yahooAddress</label>

@code{
    string googleAddress;
    string yahooAddress;

    protected override void OnInitialized()
    {
        base.OnInitialized();

        googleAddress = googleService.GetBaseUrl();
        yahooAddress = yahooService.GetBaseUrl();

    }
}

And just like that, you should have it working:

enter image description here

Let me know if you need me to explain anything else more in depth, otherwise, mark as answered if it works for you.

Upvotes: 36

Related Questions