A może by coś sobie wstrzyknąć? – spróbujmy Autofaca

Nie, nie dołączyłem do bloga sekcji związanej z substancjami psychoaktywnymi, ani też nie znajdziecie tu poradników dotyczących medycyny estetycznej :-) Jeśli jednak ten ordynarny clickbait zadziałał – zapraszam do następnego akapitu!

W niniejszym wpisie wracam do przedstawiania koncepcji i narzędzi, które poznaję i których używam pracując na VodSearcherem. Tym razem parę słów o Autofacu – kontenerze IoC. Idea odwrócenia sterowania (Inversion of Control) polega w skrócie na przeniesieniu na zewnątrz komponentu odpowiedzialności za elementy decydujące o jego zachowaniu. Zawierają się w tym poniższe zasady/zalety:

  • oddzielenie wykonania zadania w komponencie od jego implementacji
  • skupienie komponentu na zadaniu, do którego został stworzony (poprzez wyłączenie elementów kontrolnych na zewnątrz)
  • uniezależnieniu komponentu od innych elementów systemu i od sposobu, w jaki działają poprzez tworzenie zależności wyłącznie od abstrakcji
  • ograniczenie niepożądanych efektów ubocznych przy zmianie/wymianie modułu

 

Może nie brzmi to aż tak bardzo oczywiście i czytelnie, jednak w praktyce łatwo będzie zauważyć wszystkie powyższe cechy. Nieodłącznie za ideą Inversion od Control podąża wzorzec Dependency Injection. Jest to jeden ze sposobów realizacji IoC (innym jest np. wzorzec Service Locator – jednak wielokrotnie był on już określany jako anty-wzorzec :-) ) Generalnie chodzi nam o to, by wszystkie zależności, których potrzebuje dany komponent (np. Controller w Mvc, lub serwis aplikacyjny w warstwie logiki biznesowej) były określone jedynie przez abstrakcję – interfejsy zdefiniowany przez nas, natomiast rzeczywiste implementacje tych zależności były wstrzykiwane wtedy gdy są potrzebne.

Autofac jest więc narzędziem, które będzie pozwalało nam na zarejstrowanie wszystkich implementacji potrzebnych przez komponenty naszej aplikacji, a później wstrzyknięcie tych implementacji tam gdzie są wykorzystywane i potrzebne.

Najlepiej będzie pokazać to na przykładzie – w naszej aplikacji potrzebujemy dwóch dodatkowych pakietów: Autofac i Autofac.Mvc5. Instalujemy je zatem za pomocą NuGet, pamiętając z poprzedniej notki, by zainstalować je w odpowiednich wersjach.

Następnie musimy dokonać konfiguracji Autofaca poprzez utworzenie kilku jego obiektów, które będą zarządzały i przekazywały nasze zależności w odpowiednie miejsca. Najprostsza konfiguracja będzie wyglądać następująco:

var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

ContainerBuilder służy nam do określenia jakie obiekty (interfejsy i implementacje), chcemy zarejestrować, by z nich w rozmaitych miejscach systemu korzystać. Następnie rejestrujemy wszystkie kontrolery znajdujące się w aplikacji Mvc, a potem tworzymy kontener ze wszystkimi zarejestrowanymi elementami. DependencyResolver to już klasa z biblioteki integrującej Autofac z Mvc – pozwala ona na uzyskanie dostępu do zarejestrowanych przez Autofaca komponentów.

Dodajmy zatem do konfiguracji Autofaca rejestrację naszego serwisu MovieService, implementującego interfejs IMovieService. Możemy to zrobić tak:

builder.RegisterType<MovieService>().As<IMovieService>();

lub np. tak

builder.RegisterType<MovieService>().AsImplementedInterfaces();

Gdyby nasz serwis implementował więcej niż jeden interfejs druga wersja byłaby bardziej użyteczna, w naszym przypadku obie są równoważne.

Tak zarejestrowane typy możemy wstrzykiwać do komponentów. Weźmy więc kontroler, który ma nam zarządzać zgromadzonymi filmami. Możemy go zdefiniować tak:

public class MoviesController : Controller
{
    private IMovieService movieService;

    public MoviesController(IMovieService _movieService)
    {
        movieService = _movieService;
    }
}

Widzimy, że jego konstruktor wymaga jako parametru obiektu implementującego interfejs IMovieService – jak znalazł mamy taką implementację: MovieService. Skąd go weźmie? Autofac dzięki zarejestrowaniu MovieService jako implementacji IMovieService oraz rejestracji kontrolerów w naszej aplikacji będzie mógł wykorzystać utworzony DependencyResolver do podania instancji MovieService w momencie wykonania konstruktora kontrolera MoviesController. I, automagicznie, ta instancja będzie użyta np. w metodzie Index wyświetlającej listę filmów:

public ActionResult Index()
{
var config = new MapperConfiguration(cfg => cfg.CreateMap<MovieDto, MovieViewModel>()
.ForMember(dest => dest.MovieGenres,
m => m.MapFrom(src => string.Join(", ", src.MovieGenres))));

var mapper = config.CreateMapper();
var movies = movieService.GetAllMovies();
var viewModelList = mapper.Map<IEnumerable<MovieDto>, IEnumerable<MovieViewModel>>(movies);

return View();
}

Pięknie! Kontroler nie musi wiedzieć o tym, jak zaimplementowany jest serwis, którego będzie używał do operacji na filmach zgromadzonych w bazie. Nie musi też tworzyć instancji tego serwisu – wszystko dostaje z zewnątrz i może skupić się na przetwarzaniu otrzymanych danych – wszystko zgodnie z IoC.

Sama integracja Autofaca z ASP.NET MVC jest dużo obszerniejsza niż ten prosty przykład – daje on jednak, mam nadzieję, na to jak ułatwia pracę i porządkuje architekturę aplikacji.

 

Marcin

Dodaj komentarz