niedziela, 15 września 2013

Spring.net DI?

Do tej pory w większości projektów używałem jednego z dwóch kontenerów DI: Unity lub Ninject. Kontenery te są wygodne i pozwalają na dużą swobodę konfiguracji. Nowa praca, nowe wyzwania - nowy kontener - Spring.net. Jak się sprawdza w codziennej pracy w porównaniu do poprzednich?

Najpierw instalacja - tutaj z pomocą przychodzi NuGet - w wyszukiwarce wpisujemy słowo kluczowe "spring". Pierwszy wynik czyli Spring.Core to interesujący nas składnik:






Referencje dodane czas na działanie. Aby coś testować, należy przygotować pewnego rodzaju grunt. Do testów tworzymy prosty interfejs:


Code:
    public interface ICalculator
    {
        int Add(int a, int b);
        int Subtract(int a, int b);
    }

oraz klasę implementującą:


Code:
    class Calculator : ICalculator
    {
        public int Add(int a, int b)
        {
            return a + b;
        }

        public int Subtract(int a, int b)
        {
            return a - b;
        }
    }


Pierwsza zmiana w stosunku do poprzednich kontenerów DI jest taka, iż Spring.net pozwala na konfigurację wyłącznie w XML (według dokumentacji ma zostać dodana w przyszłości możliwość konfiguracji za pomocą atrybutów). Jest to z jednej strony i zaleta i wada. W mojej ocenie brak możliwości mapowania w kodzie czy też za pomocą atrybutów delikatnie skreśla tę bibliotekę z listy współczesnych frameworków DI.
Warto w tym momencie pobrać xsd springa w celu wsparcia IntelliSense. Z menu XML wybieramy opcję Schemas... i wskazujemy gdzie znajduje się plik xsd:


Dzięki temu posunięciu tworzenie xml-a będzie trochę prostsze i popełnimy mniej błędów.
Definicje obiektów możemy przechowywać w pliku XML app.config lub dowolnym innym. Przechowanie ich w app.config jest chyba najwygodniejsze - wszystkie ustawienia trzymamy w jednym pliku a nie rozrzucamy po kilku. Najłatwiejszym sposobem jest dodanie sekcji konfiguracyjnej spring i następnie odczytanie jej w aplikacji. Przykładowa rejestracja sekcji:


Code:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <sectionGroup name="spring">
      <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
      <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
    </sectionGroup>
  </configSections>

  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>

  <spring>
    <context>
      <resource uri="config://spring/objects"/>
    </context>
    <objects xmlns="http://www.springframework.net">
      <object id="calculator" type="SpringNetSample.Calculator, SpringNetSample" />
    </objects>
  </spring>
</configuration>


Samo pobranie w kodzie obiektu przebiega w następujący sposób:

Code:
            IApplicationContext applicationContext = ContextRegistry.GetContext();
            ICalculator calculator = (Calculator) applicationContext.GetObject("calculator");
            Console.WriteLine(calculator.Add(1,2));


Podsumowując prosty przykład obrazujący jak użyć Spring.net. Niestety brak możliwości konfiguracji za pomocą kodu/atrybutów nie pozwala go uznać za nowoczesny kontener DI. Z drugiej strony, zmuszając programistę do używania XML ułatwia późniejszą konfiguracje administratorom systemu.
Kolejnym minusem jest brak metod generycznych pozwalających pobrać typ który chcemy dostać - można to oczywiście obejść za pomocą metod rozszerzających.

Podsumowując - spełnia swoją rolę jako kontener DI, jednak technologicznie pozostał w epoce .NET 2.0

Nie testuję tutaj wydajności kontenera. Moim zdaniem nie ważne czy kontener tworzy 1000 obiektów na sekundę a drugi 1050, gdyż ważniejsze są, moim zdaniem, możliwości i wygoda korzystania z danego kontenera. Szybkość w przypadku użycia kontenerów DI nie ma dużego znaczenia.

Brak komentarzy:

Prześlij komentarz