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.