IoC piękna rzecz, spójrzmy jak dodać kontener IoC Autofac do aplikacji ASP.NET MVC.
W tym celu pobieramy NuGetem paczki Autofac i Autofac.Mvc5. Ponieważ jest to projekt MVC5, konieczna jest instalacja Autofac.Mvc5, dzięki temu będziemy mogli ustawić DependencyResolver na ten z Autofaca.
Następnie musimy skonfigorować nasz kontener. Przechodzimy do klasy Global.asax.cs gdzie dodajemy metodę ConfigureContainer.
1 2 3 4 5 6 7 8 |
private void ConfigureContainer() { var builder = new ContainerBuilder(); builder.RegisterControllers(typeof(MvcApplication).Assembly); builder.RegisterAssemblyModules(typeof(MvcApplication).Assembly); var container = builder.Build(); DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); } |
A jej wywołanie dodajemy do metody Application_Start()
1 2 3 4 5 6 7 8 |
protected void Application_Start() { ConfigureContainer(); AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); } |
W metodzie ConfigureContainer rejestrujemy kontrolery oraz moduły z bieżącego projektu.
Kontrolery mamy, ale nie mamy modułów. W modułach chcielibyśmy zarejestrować wszystkie typy z danego projektu. Dla przykładu załóżmy, że mamy projekt MVC i dwa pozostałe projekty, z czego jeden z nich zawiera serwisy, a drugi repozytoria. Stworzymy więc dwa moduły. Dodamy je do projektu MVC.
Każdy moduł musi dziedziczyć z klasy Module z biblioteki Autofac. W klasie modułu przeciążamy metodę Load, aby zarejestrować odpowiednie typy.
Moduł pierwszy dotyczy serwisów, chcemy zarejestrować w nim wszystkie typy z assembly Services.
1 2 3 4 5 6 7 8 |
public class ServiceModule : Module { protected override void Load(ContainerBuilder builder) { builder.RegisterAssemblyTypes(typeof(IDetermineServicesAssembly).Assembly).AsImplementedInterfaces().InstancePerRequest(); base.Load(builder); } } |
Dodajemy pusty interfejs IDetermineServicesAssembly do projektu z serwisami, służy on tylko po to aby określić z którego assembly rejestrować typy.
Kolejny moduł dotyczy repozytoriów. Analogicznie tworzymy nową klasę.
Przykład poniżej różni się od metody Load w module serwisów, ponieważ dodatkowo zarejestrowany jest typ UnitOfWork z inicjalizacją jego właściwości. Jest to przykład na to, że nic nie stoi na przeszkodzie zdefiniowania własnych customowych rejestracji.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class RepoModule : Module { protected override void Load(ContainerBuilder builder) { base.Load(builder); builder.RegisterAssemblyTypes(typeof(IDetermineRepoAssembly).Assembly).AsImplementedInterfaces().InstancePerRequest(); builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().OnActivated(c => { c.Instance.EventRepo = c.Context.Resolve<IEventRepo>(); c.Instance.EventTypeRepo = c.Context.Resolve<IEventTypeRepo>(); c.Instance.LocationRepo = c.Context.Resolve<ILocationRepo>(); c.Instance.UserRepo = c.Context.Resolve<IUserRepo>(); } ); } } |
Dodajemy pusty interfejs IDetermineRepoAssembly do projektu z repozytoriami i to wszystko. Uruchamiamy aplikacje i wszystko automagicznie działa 🙂 Autofac znajdzie wszystkie typy z danego assembly i odpowiadające im interfejsy (ponieważ zdefiniowaliśmy to w rejestracji typów).