Erhan Ballıeker

Asp.Net Core da HttpClientFactory Kullanımı (Named and Typed Clients)

Selamlar,

HttpClient Factory nin Asp.Net Core tarafında kullanımı ile ilgili yazılarımın bu bölümünde NamedClient  ve TypedClient kullanımlarına bakacağız.

Önceki yazılarımda HttpClientFactory hakkında teorik olarak getirdiklerinden ve Basic seviye de kullanımından bahsetmiştim.

Şimdi ilk olarak NamedClients dediğimiz şekilde nasıl kullanırız buna bakalım.

Aslında Basic usage dan çok fazla farklı değil ama adı üzerinde bu sefer herbir httpclientfactory e bir isim vermeye başlıyoruz. Özellikle uygulamalarımızda birden çok endpoint ile haberleşeceğimiz düşünün (ki genelde böyle olur). Bunların hepsi ile haberleşirken aynı konfigürasyonu kullanmak yeterli olmayabilir. Dolayısı bu haberleşmeler için kullanacak olduğumuz client ları ayrı ayrı tanımlayıp ayrı ayrı konfigüre etmek daha doğru olacaktır.

Bu ayırt edebilmenin de en kolay yollarından biri her bir client a bir isim vermek 🙂

Aşağıdaki örnekte bir asp.net core startup dosyasında namesclient nasıl tanımlarız bunu görüyoruz. Önceki basic usage ile kıyasladığımız da tek fark sadece string bir isim vermiş olmamız. Bu örnekte isim olarak randomuserclient dedik.

 public void ConfigureServices(IServiceCollection services)
        {
            services.Configure(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            services.AddHttpClient("randomuserclient", client =>
            {
                client.BaseAddress = new Uri("https://randomuser.me/api");
                client.DefaultRequestHeaders.Add("Accept", "application/json");
                client.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactoryTesting");
            });


            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }

Bundan sonrasında da yine Basic usage a oranla kullanımında da pek fark yok. Yine IHttpClienFactory interface imizi HomeController a otomatik olarak inject olan olacak şekilde atama yapıyoruz. Sonrasında da yine CreateClient metodu ile httpclient objemizi oluşturup işlemlerimizi yapabiliyoruz. Burada sadece tek fark CreateClient derken, Startup dosyasında vermiş olduğumuz isim ile çağırıyor olmamız.

public class HomeController : Controller
    {
        private readonly IHttpClientFactory _httpClientFactory;

        public HomeController(IHttpClientFactory httpClientFactory)
        {
            _httpClientFactory = httpClientFactory;
        }

        public async Task Index()
        {
            var client = _httpClientFactory.CreateClient("randomuserclient");
            var result = await client.GetAsync("?results=5");

            ViewBag.statusCode = result.StatusCode;
            return View();
        }

Gerçek hayat senaryolarında Basic usage ve NamedClient ları kullanıyor olmanız çok olası değil aslında. Ama varlıklarını ve kullanım şekillerini bilmekten zarar gelmezdi. 🙂

Gelelim herbir client ımızı ayrı bir sınıf olarak tanımlayacağımız kullanım şekline. Daha gerçekçi bir senaryo olarak şunu düşünebiliriz. Örneğin projemizde “Customer” entityleri için yazılmış bir API var, ve CRUD işlemleri yapıyor. Bu Api ile haberleşecek yapıyı, Client projesinde bi HttpClientFactory typed client ı olarak tanımlayıp, Gidilecek her bir farklı relative url için (/create, /update, /delete, /get vb.)  ayrı ayrı metodlar olarak tanımlamak ve birarada tutmak hoş olmaz mıydı?

Bence de hoş olurdu:) Aşağıda randomuser api ile haberleşmesini istediğimiz Endpoint için tüm işlemlerimizi yazacağımız bir TypedClien oluşturalım.

Sınıf dikkat ederseniz hiçbir özel sınıftan veya interface den miras almıyor. En altta tanımladığımız bir interface miz var. tek bir metoda sahip, Concrete class ımız olan RandomUserClient buradan implemente oluyor ve ekstra bir metoda daha sahip.

Burada en önemli nokta Client içerisnde readonly olarak tanımladığımız ve Constructor ımıza otomatik olarak inject edilecek olan HttpClient objesi. Bu obje biz bu client ımızı startup dosyasında TypedClient olarak service lere eklerken bizim için inject olucak şekilde hazırlanıyor framework tarafından.

Yani bir typed client yazarken bir properymiz HttpClient tipinde olacak, ve bu TypedClient içerisindeki network haberleşmelerini, constructor ımızla bize inject edilcek olan client ile yapacağız.

namespace HttpClientFactoryTypedClient
{
    public class RandomUserClient : IRandomUserClient
    {
        public RandomUserClient(HttpClient client)
        {
            Client = client;
        }

        public HttpClient Client { get;  }

        public async Task GetStringContentAsync()
        {
            return  await Client.GetStringAsync("?results5");
        }

        public async Task GetStringDataLength()
        {
            var result = await Client.GetStringAsync("?results5");
            return result.Length;
        }
    }

    public interface IRandomUserClient
    {
        Task GetStringDataLength();
    }
}

Bu oluşturmuş olduğumuz typed client ı startup dosyasında aşağıdaki şekilde register edebiliriz.

 public void ConfigureServices(IServiceCollection services)
        {
            services.Configure(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            //services.AddHttpClient(client =>
            //{
            //    client.BaseAddress = new Uri("https://randomuser.me/api");
            //    client.DefaultRequestHeaders.Add("Accept", "application/json");
            //    client.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactoryTesting");
            //})
            //.SetHandlerLifetime(TimeSpan.FromMinutes(5));

            services.AddHttpClient<IRandomUserClient, RandomUserClient>(client =>
            {
                client.BaseAddress = new Uri("https://randomuser.me/api");
                client.DefaultRequestHeaders.Add("Accept", "application/json");
                client.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactoryTesting");
            })
            .SetHandlerLifetime(TimeSpan.FromMinutes(2));
            


            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }

IRandomUserClient interface ile e register ediyoruz ki, ileride bu implementasyonu değiştirmek istersek, projede burası dışında başka yerde kod değiştirmek zorunda kalmayalım burada sadece

services.AddHttpClient<IRandomUserClient, NewRandomUserClient>()….

diyerek hayatımıza devam edebilelim.

Peki bu typed client ımızı projede nasıl kullanacağımıza bakarsak, aşağıdaki gibi olacak.

Bu sefer basic ve named client kullanımında olduğu gibi IHttpClienFactory değil doğrudan kendi yazdığımız client ı field olarak oluşturuyoruz ve Constructorda da bize o inject ediliiyor. Aşağıda da yine eskiden olduğu gibi kullanabiliyoruz. Tek farkı, CreateClient metodu yerine Client propertysini kullanıyoruz. Bu da hemen yukarıda kendi TypedClient ımız içerisinde tanımlamış olduğumuz HttpClient tipindeki propertymiz idi.

public class HomeController : Controller
    {
        private readonly IRandomUserClient _randomUserClient;

        public HomeController(IRandomUserClient randomUserClient)
        {
            _randomUserClient = randomUserClient;
        }

        public async Task Index()
        {
            var result = await _randomUserClient.Client.GetAsync("?results=5");
            ViewBag.statusCode = result.StatusCode;

            var stringResult = await _randomUserClient.GetStringContentAsync();

            //var contentLength = await _randomUserClient.GetStringDataLength();

            return View();
        }

 

HttpClientFactory hakkında bayağı bilgi sahibi olmuş olduk. Daha yazacaklarım var bu konuda, örneğin Refit ve Polly ile kullanımı nasıl. asp.net core dışında bu httpclient factory i nasıl kullanırız vs vs..  Şimdilik bu kadar.

Bir sonraki yazımda görüşmek üzere.