Merhaba arkadaşlar bu makalemde Web Api servisimize bir IOC (Inversion Of Control ) framework’u olan Simple Injector implementasyonundan bahsetmek istiyorum. Dependcy injection nedir makalemde IOC  prensibi uygulama yöntemlerinden biri olan DI(Dependcy Injection) hakkında konuşmuştuk.  Bu makalemde ise Simple Injector framework’u ile bu dependcylerin birbirleri ile olan bağımlılıklarının çözülmesinden ve yaşam ömürlerinden bahsetmek istiyorum.

Boş bir Web Api uygulaması oluşturalım.Ben VS2015 kullanıyorum. Farklı eki bir VS versiyonu kullanıyorsanız direk Web Api template olarak seçip oluşturabilirsiniz.

createproject

Yeni projemizi oluşturduk sonra  Simple Injector Web Api paketini kuralım. Kurulum için nuget consol’a

Install-Package SimpleInjector.Integration.WebApi

komutunu yazıp eklentiyi projemize dahil edelim. Örnek olarak kullanacağımız dependcyleri oluşturalım.

dependicies

Dependcies.cs dosyamıza aşağıdaki kod bloğunu ekleyelim.

public interface IUserDataRepository
        {
            List<Data> GetDatas();
        }

        public class SqlUserRepository : IUserDataRepository
        {
            public List<Data> GetDatas()
            {
                return new List<Data>()
                {
                    new Data() {Name = "Ali",Surname = "Devil",Age = 22},
                    new Data() {Name = "Veli",Surname = "Devil2",Age = 45},
                    new Data() {Name = "Hasan",Surname = "Devil3",Age = 36}
                };
            }
        }
        public class NoSqlUserRepository : IUserDataRepository
        {
            public List<Data> GetDatas()
            {
                return new List<Data>()
                {
                    new Data() {Name = "Elif",Surname = "Angel1",Age = 21},
                    new Data() {Name = "Nihal",Surname = "Angel2",Age = 75},
                    new Data() {Name = "Tuğba",Surname = "Angel3",Age = 45}
                };
            }
        }

        public class Data
        {
            public string Name  { get; set; }
            public string Surname { get; set; }
            public int Age { get; set; }
        }

Şimdi App_Start klasorunde yer alan WebApiConfig.cs dosyamıza geçelim ve Simple Injector ayarlarını yapalım.

public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services
            var container = new Container();
            container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
            container.Register<IUserDataRepository, SqlUserRepository>(Lifestyle.Scoped);
            container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
            container.Verify();
            GlobalConfiguration.Configuration.DependencyResolver =
                new SimpleInjectorWebApiDependencyResolver(container);
            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }

Şimdi yeni boş “user” adında bir controller oluşturalım.

newcontroller

public class UserController : ApiController
    {
        public IUserDataRepository UserDataRepository;

        public UserController(IUserDataRepository userDataRepository)
        {
            UserDataRepository = userDataRepository;
        }

        [HttpGet]
        public IEnumerable<Data> Get()
        {
            return UserDataRepository.GetDatas();
        }  
    }

Projemizi start edelim vede browserdan kendi localhost portunuza göre istek yapalım.

sqloutput

vede gördüğünüz gibi veriler geldi.Injector bizim register ettiğimiz classımızı controller’a otomatik olarak bağladı.Ornekte browser XML olarak istediği için veri XML geldi. Siz kendiniz başka bir program kullanarak controller üzerinde  hiçbir değişiklik yapmadan sadece isteğin headerını değiştirerek JSON olarak veriyi alabilirsiniz.Web api bunu sizin için yapıyor.

Dependcy register işlemini uygulama başlangıcında yaptık.Ornek olarak biz IUserDataRepository için SqlUserRepository concrete class’ını kullanıyoruz. Bunu NoSqlUserRepository olarak değiştirdinizde verilerinde değişeceğini göreceksiniz.

Burada bir diğer önemli konu ise öğenin yaşam süreci.Simple Injection için 3 adet süreç mevcut. Bunlar Transient,Scoped,Singleton.Burada biz scoped kullandık. Her istek için bize servisin yeni bir örneği geliyor.Bunu örnek üzerinden anlatırsak daha anlaşılır olabilir. Bunun için kod üzerinde bazı değişiklikler yapalım. Aşağıda değişiklik yapılan kodları yeniden paylaşıyorum

public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services
            var container = new Container();
            container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
            container.Register<IUserDataRepository, SqlUserRepository>(Lifestyle.Scoped);
            container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
            container.Verify();
            GlobalConfiguration.Configuration.DependencyResolver =
                new SimpleInjectorWebApiDependencyResolver(container);
            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
public interface IUserDataRepository
    {
        List<Data> GetDatas();
        void AddData(Data data);

    }

    public class SqlUserRepository : IUserDataRepository
    {
        public List<Data> List { get; set; }

        public SqlUserRepository()
        {
            List = new List<Data>()
                {
                    new Data() {Name = "Ali",Surname = "Devil",Age = 22},
                    new Data() {Name = "Veli",Surname = "Devil2",Age = 45},
                    new Data() {Name = "Hasan",Surname = "Devil3",Age = 36}
                };
        }
        public List<Data> GetDatas()
        {
            return List;
        }

        public void AddData(Data data)
        {
            List.Add(data);
        }
    }
    public class NoSqlUserRepository : IUserDataRepository
    {
        public List<Data> List { get; set; }

        public NoSqlUserRepository()
        {
            List = new List<Data>()
                {
                    new Data() {Name = "Elif",Surname = "Angel1",Age = 21},
                    new Data() {Name = "Nihal",Surname = "Angel2",Age = 75},
                    new Data() {Name = "Tuğba",Surname = "Angel3",Age = 45}
                };
        }
        public List<Data> GetDatas()
        {
            return List;
        }

        public void AddData(Data data)
        {
            List.Add(data);
        }
    }

    public class Data
    {
        public string Name { get; set; }
        public string Surname { get; set; }
        public int Age { get; set; }
    }
  public class UserController : ApiController
    {
        public IUserDataRepository UserDataRepository;

        public UserController(IUserDataRepository userDataRepository)
        {
            UserDataRepository = userDataRepository;
        }

        [HttpGet]
        public IEnumerable<Data> Get()
        {
            return UserDataRepository.GetDatas();
        }

        [HttpPost]
        public void AddData(Data data)
        {
            UserDataRepository.AddData(data);
        }
    }

Gördüğünüz gibi sadece AddData fonksiyonunu ekledik ve config dosyasında route ayarlarında action parametresini ekledik. Bu değişiklikleri yaptıktan sonra projeyi çalıştıralım ve bir post işlemi yapalım. Örnek Post Çağrısı:

POST http://localhost:62066/api/user/AddData HTTP/1.1
User-Agent: Fiddler
Host: localhost:62066
Content-Length: 42
Content-Type: application/json; charset=utf-8

{“Name”:”Sinan”,”Surname”:”Bir”,”Age”:100}

Post işleminden sonra normalde User controller’a get çağrısı yaptığımızda dönen yanıtlar içinde  {“Name”:”Sinan”,”Surname”:”Bir”,”Age”:100} bu kayıdın olması gerekiyor di mi ? Ama hayır biz her istek yaptığımızda container bize servisin yeni bir örneğini veriyor. Yani biz her seferinde ilk listeye erişmiş oluyoruz. Eğer life scoped değilde singleton olsaydı ne olurdu ? Bu sefer servisin sadece bir örneğini container’ın life time’ı boyunca bize verecekti. Biz farklı istekler de yapsak işlemlerin hepsi aynı nesne üzerinde işlem görecekti. Aynı çağrıyı webconfig dosyasındaki isteği singleton olarak değiştirip yaptığımızda kaydın eklendiğini görebiliriz.

Simple injector kullanmamın nedeni diğer IOC frameworklere göre biraz daha performanslı ve çoğu durumda işimizi çözüyor.

Bugunluk bahsedeceklerim bunlar. Bir başka makale ile görüşmek üzere. Hoşcakalın.