Ana Sayfa

Öğrendiklerim, Karşılaştığım Sorunlar ve Çözümleri

HttpClient ve Using Bloğu

REST in ne olduğu tarihçesi ile ilgili bilgileri daha sonra yazmak üzere direk konuya giriyorum.

Yazılım dünyasında kullanılan kaynakların serbest bırakılması gerekir. Bu eski zamanlarda manuel yapılırken geliştiriciler sağolsunlar .NETXX frameworkunda using bloğu ile işimizi bayağı bir kolaylaştırmış oldular. Blok sonunda Garbage Collector otomatik olarak devreye girerek kullanılan kaynakları serbest bırakıyor. Birçok durumda herhangi bir soruna yol açmazken bazı sınıfların bu şekilde kullanılmasının sorunlara yol açabileceği gündemde bazı tartışmalara sebebiyet vermektedir. Örneğin aşağıdaki kod bloğunu inceleyelim. Bir döngü içerisinde 10 adet HttpClient nesnesi oluşturulup kullanılıyor.

using System;
using System.Net.Http;

namespace ConsoleApplication
{
    public class Program
    {
        public static async Task Main(string[] args) 
        {
            Console.WriteLine("Starting connections");
            for(int i = 0; i<10; i++)
            {
                using(var client = new HttpClient())
                {
                    var result = await client.GetAsync("http://aspnetmonsters.com");
                    Console.WriteLine(result.StatusCode);
                }
            }
            Console.WriteLine("Connections done");
        }
    }
}

https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

Using kullanıldığı için herhangi bir sıkıntı yok gibi görünüyor. Ancak burada sorun döngü içinde oluşturulan HttpClient nesnesinin bir TCP bağlantısı açması. Bloktan çıkıldığında kaynak serbest bırakılsa bile açılan TCP connection 240 saniye boyunca TIME_WAIT durumunda kalacaktır.

C:\code\socket>NETSTAT.EXE
...
Proto Local Address Foreign Address State
TCP 10.211.55.6:12050 waws-prod-bay-017:http TIME_WAIT
TCP 10.211.55.6:12051 waws-prod-bay-017:http TIME_WAIT
TCP 10.211.55.6:12053 waws-prod-bay-017:http TIME_WAIT
TCP 10.211.55.6:12054 waws-prod-bay-017:http TIME_WAIT
TCP 10.211.55.6:12055 waws-prod-bay-017:http TIME_WAIT
TCP 10.211.55.6:12056 waws-prod-bay-017:http TIME_WAIT
TCP 10.211.55.6:12057 waws-prod-bay-017:http TIME_WAIT
TCP 10.211.55.6:12058 waws-prod-bay-017:http TIME_WAIT
TCP 10.211.55.6:12059 waws-prod-bay-017:http TIME_WAIT
TCP 10.211.55.6:12060 waws-prod-bay-017:http TIME_WAIT
TCP 10.211.55.6:12061 waws-prod-bay-017:http TIME_WAIT
TCP 10.211.55.6:12062 waws-prod-bay-017:http TIME_WAIT
TCP 127.0.0.1:1695 SIMONTIMMS742B:1696 ESTABLISHED
...

https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

Bu sayının binlerce olduğunu düşündüğümüzde varacağımız sonuç System.Net.Sockets.SocketException dır. Bu sebepten abilerimiz bu özel durum için HttpClient nesnesinin tüm program boyunca sadece bir kere oluşturulmasını ve tüm isteklerin bu örnek üzerinden yapılmasını önerirler.

using System;
using System.Net.Http;

namespace ConsoleApplication
{
    public class Program
    {
        private static readonly HttpClient Client = new HttpClient();
        public static async Task Main(string[] args) 
        {
            Console.WriteLine("Starting connections");
            for(int i = 0; i<10; i++)
            {
                var result = await Client.GetAsync("http://aspnetmonsters.com");
                Console.WriteLine(result.StatusCode);
            }
            Console.WriteLine("Connections done");
            Console.ReadLine();
        }
    }
}

https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

Görüldüğü üzere HttpClient nesnemiz static olarak tanımlanmış ve herhangi bir yerde Dispose edilmemiş. Programın çalışması süresince sadece tek bir örneği olacağı için herhangi bir hafıza ve socket hatasına yol açmadan program sonlandığında otomatik olarak dispose edilecektir.

Ancak bu istekte herhangi bir yerde header bilgisi eklenmemiştir. Benim karşılaştığım sorun yapılan isteğe ait header bilgilerinin eklenmesi aşamasında ortaya çıktı. Her kullanımda aynı header bilgilerinin eklenmesi aşağıdaki hataya sebep oldu.

“This instance has already started one or more requests. Properties can only be modified before sending the first request.”

Hatada da söylendiği gibi isteğe eklenecek özelliklerin ilk istek yapılmadan ayarlanması gerekiyor. Oluşturma aşamasında static bir metod ile değişmeyen özellikler ayarlanabilir.

public static HttpClient CreateHttpClient()
        {
            HttpClient client = new HttpClient();
            client.BaseAddress = new Uri(Constants.baseUrl);
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            return client;
        }

Değişen özellikler var ise önce var olan özelliği kaldırıp sonra ekleme yöntemiyle her istekte güncelleyebiliriz.

client.DefaultRequestHeaders.Remove("Authorization");
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);

Bütün bunlara ek olarak HttpClient nesnesinin static olarak oluşturulmasının performansa etkileri de bir başka kaynakta incelenmiş. Alıntılıyorum.

https://ankitvijay.net/2016/09/25/dispose-httpclient-or-have-a-static-instance/

WordPress.com ile böyle bir site tasarlayın
Başlayın