Proste wstrzykiwanie zależności?

Wstrzykiwanie zależności. Temat wałkowany na każdej stronie. Punkt każdego artykułu typu best practice. W związku z tym w SocialCooking, a także na tym blogu nie może zabraknąć Dependency Injection.

Na początek garść suchych faktów i definicji.

Czym jest IoC i DI (via Wikipedia)?

Inversion of Control (IoC, pol. Odwrócenie sterowania) – paradygmat polegający na przeniesieniu na zewnątrz komponentu (np. obiektu) odpowiedzialności za kontrolę wybranych czynności.

Dependency Injection (DI, pol. Wstrzykiwanie zależności) – wzorzec projektowy i wzorzec architektury oprogramowania polegający na usuwaniu bezpośrednich zależności pomiędzy komponentami na rzecz architektury typu plug-in. Jest on często utożsamiany z odwróceniem sterowania, jakkolwiek z technicznego punktu widzenia DI jest jedną ze szczególnych realizacji paradygmatu IoC.

No i wszystko już jasne prawda? 😀

Tak naprawdę w całym wstrzykiwaniu zależności zależy nam na kilku rzeczach:

  1. Nie mamy sztywnych połączeń pomiędzy komponentami (ang. loose coupling), dzięki czemu łatwiej możemy poszczególne komponenty testować.
  2. Operujemy na interfejsach, dzięki czemu w zasadzie nie obchodzi nas to co jest pod spodem. Jeżeli wstrzykujemy zależności do bazy danych nie interesuje nas czy tam na dole leży sobie MS SQL Server, MySQL, SQLite, czy (o zgrozo!) Oracle DB.

I tak naprawdę dla mnie to są 2 główne klucze dla których zawsze decyduję się na zastosowanie kontenerów IoC w moich projektach.

Co w projekcie i dlaczego?

Jak już pisałem we wcześniejszych postach, kiedy uczyłem się ASP.NET MVC korzystałem z wiedzy zawartej w książce Pro ASP.NET MVC 4 napisanej przez Adama Freemana. Autor na potrzeby projektu, który tworzył i opisywał, używał Ninjecta. No i co zrobił Kajtek? Oczywiście ślepo uwierzył, że tak będzie najlepiej i nawet nie zrobił głębszego rozeznania w temacie. Było to zdecydowanie najwygodniejsze. Zawsze pod ręką miałem opis konfiguracji, wszystko niby działało jak trzeba więc po co zmieniać. Później zmieniłem pracę i tam wykorzystany był Castle Windsor. To już delikatnie wzbudziło moją podejrzliwość. „Zaraz. Jak to. To jest gdzieś tam coś innego niż Ninject? Być może coś lepszego?” Wtedy jeszcze zignorowałem rzeczywistość i dalej tkwiłem w moim świecie idealnym, gdzie Ninject był królem (aczkolwiek od początku słabo rządzącym). Aż wreszcie kiedy postanowiłem zabrać się za SocialCooking kolega wspomniał o SimpleInjectorze. Mówił, że szybki, że łatwiejszy w konfiguracji, że po prostu działa. Zrobiłem w końcu szybki research. Jakież było moje zdziwienie jak nagle moim oczom ukazały się takie oto wykresy:

źródło: http://cardinalcore.co.uk/2015/01/28/ioc-battle-in-2015-results-using-ninject-think-again/
źródło: http://cardinalcore.co.uk/2015/01/28/ioc-battle-in-2015-results-using-ninject-think-again/
źródło: http://cardinalcore.co.uk/2015/01/28/ioc-battle-in-2015-results-using-ninject-think-again/
źródło: http://cardinalcore.co.uk/2015/01/28/ioc-battle-in-2015-results-using-ninject-think-again/

Jeszcze dodatkowe potwierdzenie na stronie: http://www.palmmedia.de/blog/2011/8/30/ioc-container-benchmark-performance-comparison.

No i wyszło w końcu to co świat chciał mi już dawno przekazać. Ninject jest do dupy…

W związku z tym poczytałem dalej i o to co wyszło.

Simple Injector konfiguracja

Jak się okazało wystarczy z NuGet’a pociągnąć paczkę SimpleInjector.Integration.WebApi.WebHost.QuickStart i nie dość, że ściągnęły się odpowiednie paczki to stworzyła się klasa SimpleInjectorWebApiInitializer.cs

public static class SimpleInjectorWebApiInitializer
    {
        ///

<summary>Initialize the container and register it as Web API Dependency Resolver.</summary>


        public static void Initialize(HttpConfiguration config)
        {
            var container = new Container();
            container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
            
            InitializeContainer(container);

            container.RegisterWebApiControllers(config);
       
            container.Verify();
            
            config.DependencyResolver =
                new SimpleInjectorWebApiDependencyResolver(container);
        }
     
        private static void InitializeContainer(Container container)
        {
            var repositoryAssembly = typeof(SCDishRepository).Assembly;

            var registrations =
                from type in repositoryAssembly.GetExportedTypes()
                where type.Namespace == "SocialCooking.Domain.Concrete"
                where type.GetInterfaces().Any()
                select new { Service = type.GetInterfaces().SingleOrDefault(), Implementation = type };

            foreach (var reg in registrations)
            {
                container.Register(reg.Service, reg.Implementation, Lifestyle.Transient);
            }
        }
    }

Jedyne co musiałem zrobić to zmienić metodę InitializeContainer według tej dokumentacji, dzięki czemu wszystkie repozytoria o określonym namespace rejestrują się automatycznie.

Na koniec dodałem jeszcze do Startup.cs


SimpleInjectorWebApiInitializer.Initialize(config);

i już wszystko powinno działać.

SocialCooking.Domain

W związku z uruchomieniem kontenera IoC w moim projekcie nareszcie mogłem też użyć projektu SocialCooking.Domain. Przerzuciłem tam wszystkie repozytoria i modele związane z autoryzacją i uwierzytelnianiem oraz dodatkowo stworzyłem jeszcze jeden kontekst (który będzie używany do wszystkiego OPRÓCZ autoryzacji). Zmiany dostępne już są do wglądu na GitHubie, a ja zabieram się za dalszą pracę nad projektem.

Related posts

  • Pingback: dotnetomaniak.pl()

  • Hej, po przeczytaniu Twojego posta następnego dnia zacząłem używać SIMPLE INJECTOR-a, przeczytałem dokumentację itd. Muszę przyznać, że robi to co powinien, nic mu nie brakuje (zakładając, że używamy go zgodnie z jego nazwą). Naprawdę wielkie dzięki.

    Na produkcji używamy jeszcze Spring .NET. Jest rozwijany tylko przez społeczność. Ale to bardzo dobry kontener z wieloma dodatkowymi funkcjami AOP, Quaraz i wiele innych.

    Jeśli chodzi o szybkość. To w sumie trzeba być ostrożnym, bo szybkość nie jest tutaj najważniejsza.

    • Kajetan Duszyński

      Spring.NET… Kurcze szczerze mówiąc nigdy nie byłem przekonany do jakichkolwiek portów między technologiami. Dlatego też nawet specjalnie na to nie patrzyłem. Ale cieszę się, że mój post pomógł w odnalezieniu czegoś co może się przydać 🙂

      Jeśli chodzi o szybkość to faktycznie najszybsze jest nie stosowanie kontenerów, ale jeśli już się na to zdecydowaliśmy to warto pomyśleć o tym żeby zastosowane rozwiązanie nie spowalniało nam całego projektu 🙂