Search code examples
c#asp.net-web-apiasp.net-core-webapidotnet-httpclienthttpclientfactory

Why HttpClient does not hold the base address even when it`s set in Startup


In my .net core web api project I would like to hit an external API so that I get my response as expected.

The way I`m registering and using the HttpClient is as follows. In the startup, I'm adding the following code which is called named typed httpclient way.

 services.AddHttpClient<IRecipeService, RecipeService>(c => {
                c.BaseAddress = new Uri("https://sooome-api-endpoint.com");
                c.DefaultRequestHeaders.Add("x-raay-key", "123567890754545645gggg");
                c.DefaultRequestHeaders.Add("x-raay-host", "sooome-api-endpoint.com");
            });

In addition to this, I have 1 service in which I inject the HttpClient.


    public class RecipeService : IRecipeService
    {
        private readonly HttpClient _httpClient;

        public RecipeService(HttpClient httpClient)
        {
           _httpClient = httpClient;
        }

        public async Task<List<Core.Dtos.Recipes>> GetReBasedOnIngAsync(string endpoint)
        {
            
            using (var response = await _httpClient.GetAsync(recipeEndpoint))
            {
                // ...
            }
        }
    }

When the httpClient is created, if I hover over the object itself, the base URI/Headers are missing, and I don't understand why exactly this is happening. I would appreciate if someone could show some light :)

UPDATE 1ST

The service is being used in one of the Controllers shown below. The service is injected by the DI and then the relative path is parsed to the service ( I assumed I already have the base URL stored in the client ) Maybe I`m doing it wrong?


namespace ABC.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class FridgeIngredientController : ControllerBase
    {
        private readonly IRecipeService _recipeService;
        private readonly IMapper _mapper;

        public FridgeIngredientController(IRecipeService recipeService, IMapper mapper)
        {
            _recipeService = recipeService;
            _mapper = mapper;
        }

        [HttpPost("myingredients")]
        public async Task<ActionResult> PostIngredients(IngredientsDto ingredientsDto)
        {
            var readyUrIngredientStr = string.Join("%2", ingredientsDto.ingredients);

            var urlEndpoint = $"recipes/findByIngredients?ingredients={readyUrIngredientStr}";
            var recipesResponse = await _recipeService.GetRecipeBasedOnIngredientsAsync(urlEndpoint);
            InMyFridgeRecipesDto recipesFoundList = new InMyFridgeRecipesDto
            {
                FoundRecipes = recipesResponse
            };

            return Ok(recipesFoundList);
        }
    }
}


Any suggestions?


Solution

  • Okay so I will answer my post because with the suggested TYPED way of doing it was causing problems with the values not being set inside the httpClient, E.G BaseAddress was always null.

    In the startup I was trying to go with typed httpclient e.g

    services.AddHttpClient<IReService, ReService>(c => ...
    

    But instead of doing that, I choose the to go with the Named client. Which means that in the startup we need to register the httpclient like this

    services.AddHttpClient("recipeService", c => {
    ....
    
    

    And then in the service itself I used HttpClientFactory like below.

     private readonly IHttpClientFactory _httpClientFactory;
    
            public RecipeService(IHttpClientFactory httpClientFactory)
            {
                _httpClientFactory = httpClientFactory;
            }
    
            public async Task<List<Core.Dtos.Recipes>> GetRecipeBasedOnIngredientsAsync(string recipeEndpoint)
            {
                var client = _httpClientFactory.CreateClient("recipeService");
    
                using (var response = await client.GetAsync(client.BaseAddress + recipeEndpoint))
                {
                    response.EnsureSuccessStatusCode();
    
                    var responseRecipies = await response.Content.ReadAsStringAsync();
                    var recipeObj = ConvertResponseToObjectList<Core.Dtos.Recipes>(responseRecipies);
    
                    return recipeObj ?? null;
                }
            }