3
\$\begingroup\$

Hi I have a requirement where in I have to call two different client methods from same api in .NET Core and I have structured my code as follows. THis is working fine but Please give me your valuable inputs or suggestions for improvements.

I am using HTTPClientFactory to create my clients as shown below:

  public class CustomerApiClient : ICustomerApiClient
    {
        private readonly HttpClient _httpClientCustomer;
        private readonly HttpClient _httpClientProduct;
        private readonly ILogger _logger;
        private readonly IHttpClientFactory _httpClientFactory;
        private readonly IConfiguration _configuration;

        public CustomerApiClient(IHttpClientFactory httpClientFactory, IConfiguration configuration, ILogger<CustomerApiClient> logger)
        {
            this._logger = logger;
            this._httpClientFactory = httpClientFactory;
            this._configuration = configuration;

            _httpClientCustomer = httpClientFactory.CreateClient("CustomerService");
            var authApiKey = configuration.GetSection("CustomerAuthApiKey")?.Value;
            _httpClientCustomer.DefaultRequestHeaders.Add("AuthApiKey", authApiKey);

            _httpClientProduct = httpClientFactory.CreateClient("ProductService");
            var authApiKeyImageManagementService = configuration.GetSection("ProductAuthApiKey")?.Value;
            _httpClientProduct.DefaultRequestHeaders.Add("AuthApiKey", authApiKeyImageManagementService);


        }


        public virtual async Task<object> GetCustomerDetailsAsync(int customerId)
        {
            _logger.LogDebug("customerId");

            var uri = string.Concat(_httpClientCustomer?.BaseAddress, $"/GetCustomerBycustomerId?customer={customerId}");
            using (var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri))
            {
                using (var response = await _httpClientCustomer.SendAsync(requestMessage, CancellationToken.None))
                {
                    var stream = await response.Content.ReadAsStreamAsync();

                    var strStream = await response.Content.ReadAsStringAsync();

                    if (response.IsSuccessStatusCode)
                    {
                        if (strStream.ToLower() == "null")
                        {
                            return null;
                        }

                        JObject respJobject = JObject.Parse(strStream);
                        var resultCustomer = respJobject;

                    }
                }
            }

            // the resultCustomer object wil have productId in it. Will be using the productId for below  service -- /product/productId . Have not written the code for it so hardcoded it as 1102

            var uriProductService = string.Concat(_httpClientProduct?.BaseAddress, $"/product/1102");

            using (var requestMessage1 = new HttpRequestMessage(HttpMethod.Get, uriProductService))
            {
                using (var response = await _httpClientProduct.SendAsync(requestMessage1, CancellationToken.None))
                {
                    var stream1 = await response.Content.ReadAsStreamAsync();

                    var strStream1 = await response.Content.ReadAsStringAsync();

                    if (response.IsSuccessStatusCode)
                    {
                       return ApiHelper.DeserializeJson<System.Collections.Generic.ICollection<Product>>(stream1);
                    }

                    var content = await ApiHelper.StreamToStringAsync(stream1);
                    throw new ApiException
                    {
                        StatusCode = (int)response.StatusCode,
                        Content = content
                    };
                }
            }
        }

    }

My Startup.cs file contains the following in ConfigureDependencies method

serviceCollection.AddHttpClient("CustomerService", im =>
            {
                im.BaseAddress = new Uri("https://Testserver-Phse2.net/Shared/CustomerService/api/v1/Customers");
            });

            serviceCollection.AddHttpClient("ProductService", dc =>
            {
                dc.BaseAddress = new Uri(Configuration.GetSection("ApiUrls:ProductServiceApi")?.Value); 
            });

            serviceCollection.AddScoped<ICustomerApiClient, CustomerApiClient>();

And if you observe this line JObject respJobject = JObject.Parse(strStream); I am converting my stream to JObject and then using linq to loop through it. Is it a good thing or should I create a localized DTO Customer object and deserialize into it like shown below.. Which approach is better in terms of optimization

 var objectResponse_ = ApiHelper.DeserializeJson<Customer>(stream)

ApiHelper.cs

public static class APiHelper
   
              public static T DeserializeJsonFromStream<T>(Stream stream)
        {
            if (stream == null || !stream.CanRead)
                return default(T);

            using (var sr = new StreamReader(stream))
            using (var jtr = new JsonTextReader(sr))
            {
                var js = new JsonSerializer();
                js.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
                var searchResult = js.Deserialize<T>(jtr);
                return searchResult;
            }
        }
}
\$\endgroup\$
9
  • \$\begingroup\$ Could you fix the typos in the code first? \$\endgroup\$
    – aepot
    Commented Apr 12, 2021 at 17:42
  • 1
    \$\begingroup\$ I have done them. Sorry for it. \$\endgroup\$
    – chiru1983
    Commented Apr 12, 2021 at 17:55
  • \$\begingroup\$ Still typos there. Doesn't compile. \$\endgroup\$
    – aepot
    Commented Apr 12, 2021 at 18:09
  • 1
    \$\begingroup\$ thank you for the tip. please check now \$\endgroup\$
    – chiru1983
    Commented Apr 12, 2021 at 18:44
  • 1
    \$\begingroup\$ Thanks for keeping up with me aepot. I am a newbie to this forum so kindly excuse my errors. I have updated my question. \$\endgroup\$
    – chiru1983
    Commented Apr 14, 2021 at 3:25

1 Answer 1

1
\$\begingroup\$

Magic Strings
Fix the magic strings issue and use constants instead for your string inputs - it'll make code changes far easier to do

Unclear intention based on naming
_logger.LogDebug("customerId"); are you intending to output the customerId passed into the method there? Its not clear.

Unnecessary URI declaration
var uri = string.Concat(_httpClientCustomer?.BaseAddress, $"/GetCustomerBycustomerId?customer={customerId}"); That base address can be setup when you create the HTTP Client. So the only URL you need to pass into the call to: using (var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri)) is the end part of the URI

Reading the Response Stream Multiple Times
You are reading the stream twice, but only using one of them?

var stream = await response.Content.ReadAsStreamAsync();

var strStream = await response.Content.ReadAsStringAsync();

Null Check Required Values
Do you need null checks for these values and only add the header if the value exists?

_httpClientCustomer.DefaultRequestHeaders.Add("AuthApiKey", authApiKey);
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.