question

PrathameshShende avatar image
0 Votes"
PrathameshShende asked AgaveJoe edited

HttpClient Not fetching BaseAddress

I have create
Blazore WASM App and with Identity Server 4 So
IHttpClientFactory and add default httpClient scope
but its showin Null HttpClient.BaseAddress after I fetching into services.cs file

this is files
Program.cs

public class Program
{
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.Logging.SetMinimumLevel(LogLevel.Debug);
//builder.Logging.AddProvider(new CustomLoggingProvider(LogLevel.Error));
builder.RootComponents.Add<App>("#app");

         builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

         // We register a named HttpClient here for the API
         builder.Services.AddHttpClient("api")
             .AddHttpMessageHandler(sp =>
             {
                 var handler = sp.GetService<AuthorizationMessageHandler>()
                     .ConfigureHandler(
                         authorizedUrls: new[] { new Uri(builder.HostEnvironment.BaseAddress).ToString() },
                         scopes: new[] { "api1", "email" });
                 return handler;
             });

         // we use the api client as default HttpClient
         builder.Services.AddScoped(sp => sp.GetService<IHttpClientFactory>().CreateClient("api"));

         builder.Services
             .AddOidcAuthentication(options =>
             {
                 builder.Configuration.Bind("oidc", options.ProviderOptions);
                 options.UserOptions.RoleClaim = "role";
             }).AddAccountClaimsPrincipalFactory<ArrayClaimsPrincipalFactory<RemoteUserAccount>>();


         builder.Services.AddScoped<SetupsService>();
         await builder.Build().RunAsync();
     }
 }


public class SetupsService
{

     HttpClient _httpClient;
     IHttpClientFactory _httpClientFactory;
     public SetupsService(IHttpClientFactory httpClientFactory)
     {
         _httpClientFactory = httpClientFactory;
         _httpClient = _httpClientFactory.CreateClient("api");
     }

     public async Task<List<Setup>> GetSetupsAsync()
     {
         return await _httpClient.GetFromJsonAsync<List<Setup>>($"{ _httpClient.BaseAddress } api/Setups");
     }

``}

here its show null and not fetching baseaddress

dotnet-aspnet-core-blazor
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

PrathameshShende avatar image
0 Votes"
PrathameshShende answered PrathameshShende commented

If I Remove the AddHttpClient("api") code then
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
it will fetch code directly and it will set the base Address as per environment.

Identity Server 4 Applied IHttpClientFactory that's why this problem occurs
Is there any option to Set Base Adderss in Program.cs File and use it into service.cs files?

· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

No, leave the AddHttpClient call. As I mentioned you will use your existing setup code. Just add the necessary line to set the base address as well. Generally it looks something like this:

services.AddHttpClient("api", c => {
   c.BaseAddress = new Uri("https://tempuri.org/");
});


The properties on HttpClient are designed to be set before the first usage of the client. The current implementation, the last time I looked, doesn't fail if you change the properties after the fact but you can get into tough situations if you are dynamically changing the values after the client is created. To change per-request values you would go to the HttpRequestMessage instead.

0 Votes 0 ·

It works, Thanks

0 Votes 0 ·
cooldadtx avatar image
0 Votes"
cooldadtx answered PrathameshShende commented

I don't see in your HttpClient setup code that you ever set BaseAddress. You define a custom message handler but nowhere is the base address set.

Also, in your actual client usage you shouldn't include the base address, it is added automatically. When you provide a URI to any of the methods it looks to see if it is an absolute URL or not. If it is absolute then it uses the address as is. This is the non-standard approach, in my opinion. If you go this route then you don't need to set BaseAddress as it won't use it.

However in most cases you use a relative URL. In that case the BaseAddress value is automatically added to the call. This is the preferred approach as each client should ideally be for the same base address and only the resource(s) change. Note however that when setting the bae address ensure it ends with a slash. In older versions of the implementation (may not be an issue now) the client doesn't join the addresses properly without it.

//Set up (just an example of setting the base address, use your existing code
new HttpClient() { BaseAddress = "https://www.tempuri.org/" };

//Usage
client.GetFromJsonAsync<List<Setup>>("api/setups");
· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

If I Remove the AddHttpClient("api") code then
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
it will fetch code directly and it will set the base Address as per environment.

Identity Server 4 Applied IHttpClientFactory that's why this problem occurs
Is there any option to Set Base Adderss in Program.cs File and use it into service.cs files?

0 Votes 0 ·
AgaveJoe avatar image
0 Votes"
AgaveJoe answered AgaveJoe edited

I think you misunderstand named HttpClients and factories. You get to configure the HttpClient factory to return a named client. The named client can have a base address that you configure. This is very convenient when you have one or many REST services. Anyway, the standard docs cover all the details. I think you'll be interested in giving the docs a good reading.

Keep in mind your current configuration always points to the current host. That might be fine if your application never calls a remote service. I usually have configuration similar to the following where the API URL is stored in configuration.

 var DefaultApi = builder.Configuration.GetValue<string>("ApiUrl:DefaultApi");
    
 builder.Services.AddScoped(sp => 
     new HttpClient { BaseAddress = new Uri(DefaultApi) });

Configuration

 {
   "ApiUrl": {
     "DefaultApi": "https://localhost:44384/"
   }






5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.