Miroslav Holec
Premium

Vyzkoušejte IoC kontejner AutoFac

Miroslav Holec   12. července 2015upd. 29. března 2016

Tento článek je již velmi zastaralý. Článek nemusí popisovat aktuální stav technologie, ideální řešení a můj současný pohled na dané téma.

Přestože jsem více než 2 roky pracoval s Castle Windsor, poslední dobou mi stále častěji pod rukama probíhá kontejner AutoFac. V tomto článku shrnu vybrané vlastnosti a možnosti nastavení.

Dokumentace

Dlouhou dobu jsem upřednostňoval Castle Windsor, který má sice mizernou dokumentaci ale na druhou stranu i silnou komunitu, která zajišťuje dobrou podporu na Stack Overflow. AutoFac má velmi podrobnou dokumentaci a celkem srozumitelné nastavení všeho, co může vývojář potřebovat. Z technického hlediska nemá už moc smysl IoC kontejnery srovnávat, protože se liší jen použitím a případně rychlostí. Ta je stejně jako i Windsor Castle velmi dobrá.

Podpora frameworků a komponent

AutoFac nabízí možnost integrace do MVC (až do verze 5), Web API 2, OWIN, WCF nebo například Web Forms. Nechybí podpora řady komponent, jako časostroj Quartz.NET nebo logovací nástroje NLog / Log4Net.

Install-Package Autofac
Install-Package Autofac.Mvc5
Install-Package Autofac.WebApi2

Konfigurace MVC 5

Konfigurace probíhá stejně jako v případě všech kontejnerů v global.asax.cs v metodě Application_Start().

protected void Application_Start()
{
	var builder = new ContainerBuilder();

	// Register your MVC controllers.
	builder.RegisterControllers(typeof(MvcApplication).Assembly);

	// OPTIONAL: Register model binders that require DI.
	builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
	builder.RegisterModelBinderProvider();

	// OPTIONAL: Register web abstractions like HttpContextBase.
	builder.RegisterModule<AutofacWebTypesModule>();

	// OPTIONAL: Enable property injection in view pages.
	builder.RegisterSource(new ViewRegistrationSource());

	// OPTIONAL: Enable property injection into action filters.
	builder.RegisterFilterProvider();

	// Set the dependency resolver to be Autofac.
	var container = builder.Build();
	DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}

Nastavení je samozřejmě vhodnější provést v samostatných třídách, než je přímo vypisovat v Application_Start().

AutoFac má speciální modul, který umí zaregistrovat řadu webových abstraktních tříd, např.: HttpRequestBase, RequestContext nebo užitečný UrlHelper.

Property Injection

Trochu přes ruku je s AutoFac řešena property injection. Zatímco například v Ninjectu stačí uvést nad property datovou anotaci [Inject], v AutoFac je nutná konfigurace.

builder.RegisterType<MyService>().As<IService>().PropertiesAutowired();

Teprve pro takto registrované komponenty je možné aplikovat property injection.

Scanování assemblies a hromadná registrace

Typický požadavek na IoC kontejner je hromadná registrace (repositářů, services apod.)

var assembly = Assembly.GetExecutingAssembly();

builder.RegisterAssemblyTypes(assembly)
   .Where(t => t.Name.EndsWith("Repository"))
   .Except<ExtraRepository>()
   .AsImplementedInterfaces();

Lifetime

Další častý požadavek je možnost nastavení životnosti instancí. V případě webových aplikací je často používaná InstancePerRequest:

builder.RegisterType<MyContext>()
	.As<IDbContext>()
	.WithParameter("connectionString", "MyConnectioStringName")
	.InstancePerRequest();

Dále jsou dostupné InstancePerDependency (ve Windsoru Transient), která vytváří unikátní instance pro každý request dané služby nebo například SingleInstance (jinak Singleton) aj.

Property Injection pro filter atributy

V MVC aplikacích se nedá obejít bez vytváření různých action filtrů. V těch je často potřeba sáhnout na repositář nebo na službu (kvůli logování, ověřování uživatele aj.). V případě AutoFac stačí přidat konfiguraci:

builder.RegisterFilterProvider();

a následně je možné vytvářet snadno různé vlastní atributy:

public class LogFilter : ActionFilterAttribute
{
	public ILogger Logger { get; set; }

	public override void OnActionExecuting(ActionExecutingContext filterContext)
	{
		Logger.Log("Executing!");
	}
}

nebo zmíněné autorizační atributy:

public class AuthAttribute : AuthorizeAttribute
{
	public IUserRepository UserRepository { get; set; }

	protected override bool AuthorizeCore(HttpContextBase httpContext)
	{
		// logic here
		return true;
	}
}

Logování

Přímo v dokumentaci AutoFac je popsána integrace log4net, nicméně na nuget.org se už dají najít integrační moduly pro většinu běžně používaných logovacích frameworků.

Install-Package log4net.AutoFac
Install-Package Autofac.Extras.NLog

Závěr

Přestože jsem se už na Castle Windsor zvykl, pomalu začínám přecházet na AutoFac. Nabízí v podstatě všechno, co potřebuji a je mnohem lépe dokumentovaný. Příjemná je i syntaxe a neustále rostoucí komunita vývojářů, kteří vytváří různá extra rozšíření a jsou ochotni na Stack Overflow řešit specifické problémy.