C
C#3mo ago
Alex

✅ Configure base address in HttpClient in Dependency Injection

Hi! I want to add http client with configuration for the service ILocationService
builder.Services.AddHttpClient<NominatimLocationService>(client =>
{
client.BaseAddress = new Uri("https://nominatim.openstreetmap.org");
client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (compatible; AcmeInc/1.0)");
});
builder.Services.AddHttpClient<NominatimLocationService>(client =>
{
client.BaseAddress = new Uri("https://nominatim.openstreetmap.org");
client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (compatible; AcmeInc/1.0)");
});
It has an implementation NominatimLocationService where I get this http client. The problem is that I get default http client without configuration. What have I done wrong? Also is there a way to configure HttpClientHander in Dependency Injection? I need it to set automatic decompression
public class NominatimLocationService:ILocationService
{
private readonly HttpClient _httpClient;

public NominatimLocationService(HttpClient httpClient)
{
_httpClient = httpClient;
}
}
public class NominatimLocationService:ILocationService
{
private readonly HttpClient _httpClient;

public NominatimLocationService(HttpClient httpClient)
{
_httpClient = httpClient;
}
}
34 Replies
WEIRD FLEX
WEIRD FLEX3mo ago
well but you are saying "configuration for the service ILocationService", not NominatimLocationService
Alex
Alex3mo ago
ILocationService is an interface for NominatimLocationService that I use in controller to fetch location data
WEIRD FLEX
WEIRD FLEX3mo ago
yes, but you are registering custom httpclient with NominatimLocationService, not ILocationService i don't know if that's an issue, but still if you are injecting NominatimLocationService via ILocationService then you should probably change one of the two
Alex
Alex3mo ago
I tried registering for ILocationService and NominatimLocationService and still getting exception
"message": "An invalid request URI was provided. Either the request URI must be an absolute URI or BaseAddress must be set."
"message": "An invalid request URI was provided. Either the request URI must be an absolute URI or BaseAddress must be set."
WEIRD FLEX
WEIRD FLEX3mo ago
and this is when trying to make a call, not when constructing NominatimLocationService, right?
Alex
Alex3mo ago
Yes I'm calling method and passing relative address
public async Task<IEnumerable<LocationResponse>> FindByQueryAsync(string query)
{
// https://nominatim.openstreetmap.org/search.php?q=tes&format=jsonv2
HttpResponseMessage responseMessage = await _httpClient.GetAsync($"search.php?q={query}&format=jsonv2");

if (!responseMessage.IsSuccessStatusCode)
{
throw new BadRequestException($"Failed to get locations: {responseMessage.ReasonPhrase}");
}

IEnumerable<LocationResponse>? locations = await responseMessage.Content.ReadFromJsonAsync<IEnumerable<LocationResponse>>();

return (locations ?? Array.Empty<LocationResponse>())
.OrderBy(l => l.PlaceRank)
.ThenByDescending(l => l.Importance);
}
public async Task<IEnumerable<LocationResponse>> FindByQueryAsync(string query)
{
// https://nominatim.openstreetmap.org/search.php?q=tes&format=jsonv2
HttpResponseMessage responseMessage = await _httpClient.GetAsync($"search.php?q={query}&format=jsonv2");

if (!responseMessage.IsSuccessStatusCode)
{
throw new BadRequestException($"Failed to get locations: {responseMessage.ReasonPhrase}");
}

IEnumerable<LocationResponse>? locations = await responseMessage.Content.ReadFromJsonAsync<IEnumerable<LocationResponse>>();

return (locations ?? Array.Empty<LocationResponse>())
.OrderBy(l => l.PlaceRank)
.ThenByDescending(l => l.Importance);
}
WEIRD FLEX
WEIRD FLEX3mo ago
as of now i wouldn't know better than this
-client.BaseAddress = new Uri("https://nominatim.openstreetmap.org");
+client.BaseAddress = new Uri("https://nominatim.openstreetmap.org/");
-client.BaseAddress = new Uri("https://nominatim.openstreetmap.org");
+client.BaseAddress = new Uri("https://nominatim.openstreetmap.org/");
also because i have to go to sleep
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
WEIRD FLEX
WEIRD FLEX3mo ago
fair enough
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
Alex
Alex3mo ago
The problem is that in constructor I receive httpClient without baseUrl that I configured in Program.cs
No description
Alex
Alex3mo ago
I tried the ways you suggested but they didn't solve my problem
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
Alex
Alex3mo ago
I changed to this but base address is still null If I set base address in constructor, everything works fine
public class NominatimLocationService:ILocationService
{
private readonly HttpClient _httpClient;

public NominatimLocationService(HttpClient httpClient)
{
_httpClient = httpClient;
_httpClient.BaseAddress = new Uri("https://nominatim.openstreetmap.org");
_httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (compatible; AcmeInc/1.0)");
}
}
public class NominatimLocationService:ILocationService
{
private readonly HttpClient _httpClient;

public NominatimLocationService(HttpClient httpClient)
{
_httpClient = httpClient;
_httpClient.BaseAddress = new Uri("https://nominatim.openstreetmap.org");
_httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (compatible; AcmeInc/1.0)");
}
}
rodrigovaz
rodrigovaz3mo ago
afaik, your configuration here seems right, Maybe if you show the rest of your program/startup.cs there might be something weird going on there and would be easier to troubleshoot Nonetheless, this is ok As long as the HttpClient being supplied is transient, there's no downside
rodrigovaz
rodrigovaz3mo ago
Microsoft does it in their examples: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-8.0#typed-clients
public class GitHubService
{
private readonly HttpClient _httpClient;

public GitHubService(HttpClient httpClient)
{
_httpClient = httpClient;

_httpClient.BaseAddress = new Uri("https://api.github.com/");

// using Microsoft.Net.Http.Headers;
// The GitHub API requires two headers.
_httpClient.DefaultRequestHeaders.Add(
HeaderNames.Accept, "application/vnd.github.v3+json");
_httpClient.DefaultRequestHeaders.Add(
HeaderNames.UserAgent, "HttpRequestsSample");
}

public async Task<IEnumerable<GitHubBranch>?> GetAspNetCoreDocsBranchesAsync() =>
await _httpClient.GetFromJsonAsync<IEnumerable<GitHubBranch>>(
"repos/dotnet/AspNetCore.Docs/branches");
}
public class GitHubService
{
private readonly HttpClient _httpClient;

public GitHubService(HttpClient httpClient)
{
_httpClient = httpClient;

_httpClient.BaseAddress = new Uri("https://api.github.com/");

// using Microsoft.Net.Http.Headers;
// The GitHub API requires two headers.
_httpClient.DefaultRequestHeaders.Add(
HeaderNames.Accept, "application/vnd.github.v3+json");
_httpClient.DefaultRequestHeaders.Add(
HeaderNames.UserAgent, "HttpRequestsSample");
}

public async Task<IEnumerable<GitHubBranch>?> GetAspNetCoreDocsBranchesAsync() =>
await _httpClient.GetFromJsonAsync<IEnumerable<GitHubBranch>>(
"repos/dotnet/AspNetCore.Docs/branches");
}
Make HTTP requests using IHttpClientFactory in ASP.NET Core
Learn about using the IHttpClientFactory interface to manage logical HttpClient instances in ASP.NET Core.
rodrigovaz
rodrigovaz3mo ago
For the automatic decompression, use the extension method ConfigurePrimaryHttpMessageHandler after you do AddHttpClient<> return an action that instantiates the HttpMessageHandler with automatic decompression
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
WEIRD FLEX
WEIRD FLEX3mo ago
eventually he could try starting from scratch to just try the httpclient injection
Alex
Alex3mo ago
Program.cs
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Add Logger
builder.Logging.ClearProviders();
builder.Logging.AddConsole();
// Add HttpClient
builder.Services.AddHttpClient<ILocationService,NominatimLocationService>(client =>
{
client.BaseAddress = new Uri("https://nominatim.openstreetmap.org");
client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (compatible; AcmeInc/1.0)");
});
builder.Services.AddRepositories();
// Add Services
builder.Services.AddServices();

//Add Background services
// builder.Services.AddHostedService<UpdateCacheBackgroundService>();
// builder.Services.AddHostedService<IndexCreationService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
else
{
app.UseHttpsRedirection();
}
app.UseAuthorization();
app.UseMiddleware<ExceptionHandlerMiddleware>();
app.MapControllers();
app.Run();
}
}
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Add Logger
builder.Logging.ClearProviders();
builder.Logging.AddConsole();
// Add HttpClient
builder.Services.AddHttpClient<ILocationService,NominatimLocationService>(client =>
{
client.BaseAddress = new Uri("https://nominatim.openstreetmap.org");
client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (compatible; AcmeInc/1.0)");
});
builder.Services.AddRepositories();
// Add Services
builder.Services.AddServices();

//Add Background services
// builder.Services.AddHostedService<UpdateCacheBackgroundService>();
// builder.Services.AddHostedService<IndexCreationService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
else
{
app.UseHttpsRedirection();
}
app.UseAuthorization();
app.UseMiddleware<ExceptionHandlerMiddleware>();
app.MapControllers();
app.Run();
}
}
Search class
public class NominatimLocationService:ILocationService
{
private readonly HttpClient _httpClient;

public NominatimLocationService(HttpClient httpClient)
{
_httpClient = httpClient;
// _httpClient.BaseAddress = new Uri("https://nominatim.openstreetmap.org");
// _httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (compatible; AcmeInc/1.0)");
}

public async Task<IEnumerable<LocationResponse>> FindByQueryAsync(string query)
{
// https://nominatim.openstreetmap.org/search.php?q=tes&format=jsonv2
HttpResponseMessage responseMessage = await _httpClient.GetAsync($"search.php?q={query}&format=jsonv2");

if (!responseMessage.IsSuccessStatusCode)
{
throw new BadRequestException($"Failed to get locations: {responseMessage.ReasonPhrase}");
}

IEnumerable<LocationResponse>? locations = await responseMessage.Content.ReadFromJsonAsync<IEnumerable<LocationResponse>>();

return (locations ?? Array.Empty<LocationResponse>())
.OrderBy(l => l.PlaceRank)
.ThenByDescending(l => l.Importance);
}
}
public class NominatimLocationService:ILocationService
{
private readonly HttpClient _httpClient;

public NominatimLocationService(HttpClient httpClient)
{
_httpClient = httpClient;
// _httpClient.BaseAddress = new Uri("https://nominatim.openstreetmap.org");
// _httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (compatible; AcmeInc/1.0)");
}

public async Task<IEnumerable<LocationResponse>> FindByQueryAsync(string query)
{
// https://nominatim.openstreetmap.org/search.php?q=tes&format=jsonv2
HttpResponseMessage responseMessage = await _httpClient.GetAsync($"search.php?q={query}&format=jsonv2");

if (!responseMessage.IsSuccessStatusCode)
{
throw new BadRequestException($"Failed to get locations: {responseMessage.ReasonPhrase}");
}

IEnumerable<LocationResponse>? locations = await responseMessage.Content.ReadFromJsonAsync<IEnumerable<LocationResponse>>();

return (locations ?? Array.Empty<LocationResponse>())
.OrderBy(l => l.PlaceRank)
.ThenByDescending(l => l.Importance);
}
}
The place where I use search class
[Route("api/[controller]")]
[ApiController]
public class LocationsController : ControllerBase
{
private readonly ILocationService _locationService;

public LocationsController(ILocationService locationService)
{
_locationService = locationService;
}

[HttpGet("search")]
public async Task<IActionResult> Search([FromQuery] string? query)
{
if(string.IsNullOrEmpty(query))
{
throw new BadRequestException("Search parameter 'query' is required");
}

IEnumerable<LocationResponse> locations = await _locationService.FindByQueryAsync(query);

return Ok(locations);
}
}
[Route("api/[controller]")]
[ApiController]
public class LocationsController : ControllerBase
{
private readonly ILocationService _locationService;

public LocationsController(ILocationService locationService)
{
_locationService = locationService;
}

[HttpGet("search")]
public async Task<IActionResult> Search([FromQuery] string? query)
{
if(string.IsNullOrEmpty(query))
{
throw new BadRequestException("Search parameter 'query' is required");
}

IEnumerable<LocationResponse> locations = await _locationService.FindByQueryAsync(query);

return Ok(locations);
}
}
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
MODiX
MODiX3mo ago
If your code is too long, you can post to https://paste.mod.gg/ and copy the link into chat for others to see your shared code!
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
rodrigovaz
rodrigovaz3mo ago
Because he mentions it in his post?
No description
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
rodrigovaz
rodrigovaz3mo ago
Yeah, I attempted to reproduce the error here and couldn't get it too
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
Alex
Alex3mo ago
Sorry I didn't answer earlier, here is the link: https://github.com/aleksandrmakarov-dev/traffic-visualizer
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
Alex
Alex3mo ago
thank you for the answer and sorry for wasting your time, maybe error is related to my computer if it works fine on yours. If you have any experience with Redis, what .net library can you recommend? I get every minute >150 data items about road situation, item has nested structure and I need to delete previous data using prefix and save new items
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
Alex
Alex3mo ago
do you mean create a new post in help section?
Unknown User
Unknown User3mo ago
Message Not Public
Sign In & Join Server To View
Alex
Alex3mo ago
okay, got it