Reputation:
I want to implement factory pattern in Autofac. This is how it was done in Ninject:
Bind<ICarFilter>().To<CarFilter >();
Bind<IBikeFilter>().To<BikeFilter>();
Bind<IFilterFacade>().ToFactory().InSingletonScope();
This is a definitnion of IFilterFacade
public interface IFilterFacade
{
ICarFilter CreateCarFilter();
IBikeFIlter CreateBikeFilter();
}
If I want an instance of CarFilter type, all I need to do is the following:
public class HomeController(IFilterFacade filterFacade)
{
FilterFacade = filterFacade;
}
public IFilterFacade FilterFacade { get;set; }
public ActionResult Index()
{
var bikeFilter = FilterFacade.CreateBikeFilter();
}
Any example how to do that in AutoFac. I checked AutoFac documentation, but was not able to find the answer or example.
Upvotes: 7
Views: 7985
Reputation: 4735
I wrote a NuGet which does exactly this but over IServiceCollection
.
https://github.com/czmirek/AddFactoryExtension
https://www.nuget.org/packages/AddFactoryExtension
Upvotes: 1
Reputation: 16187
There is no equivalent of ToFactory
in Autofac but you can easily implement a generic factory equivalent.
public interface IFilterFactory
{
TFilter Get() where TFilter : IFilter;
}
public class FilterFactory : IFilterFactory
{
public FilterFactory(ILifetimeScope scope)
{
this._scope = scope;
}
private readonly ILifetimeScope _scope;
public TFilter Get<TFilter>()
{
return this._scope.Resolve<TFilter>();
}
}
Then register it like this :
builder.RegisterType<FilterFactory>().As<IFilterFactory>();
builder.RegisterType<BikeFilter>().As<IBikeFilter>();
builder.RegisterType<CarFilter>().As<ICarFilter>();
and use it this way
public class HomeController
{
private readonly IFilterFactory _filters;
public HomeController(IFilterFactory filters)
{
this._filters = filters;
}
public ActionResult Index()
{
var bikeFilter = this._filters.Get<IBikeFilter>();
// ...
}
}
I rename the Create
method to Get
because the method will look up an instance in the lifetime scope and create one only if needed.
Another possible solution may be to use Named and Keyed Service and the built-in IIndex
type.
builder.RegisterType<BikeFilter>().Named<IFilter>("Bike");
builder.RegisterType<CarFilter>().Named<IFilter>("Car");
then on your controller
public class HomeController
{
private readonly IIndex<String, IFilter> _filters;
public HomeController(IIndex<String, IFilter> filters)
{
this._filters = filters;
}
public ActionResult Index()
{
var bikeFilter = this._filters["Bike"];
// ...
}
}
Upvotes: 9
Reputation: 8498
Autofac has no such feature as dynamically implementing user-defined factory interface. It does allow binding to delegates, but it's not the same.
If you want to receive a kind of factory in constructor, then obtain individual components from that factory in relevant methods, it is definitely possible with Autofac.
Composition root
Here I register individual components as singletons (this was the behavior with Ninject, if I get it correctly), but you can use any lifetime option that fits your requirements.
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<BikeFilter>().As<IBikeFilter>().SingleInstance();
builder.RegisterType<CarFilter>().As<ICarFilter>().SingleInstance();
Controller
public class HomeController
{
private readonly IComponentContext _components;
public HomeController(IComponentContext components)
{
_components = components; // instead of factory interface
}
public ActionResult Index()
{
var bikeFilter = _components.Resolve<IBikeFilter>();
// ...
}
}
BTW
I think that factory interface is a nice feature of Ninject. Another added value of it is allowing to explore through IntelliSense. In your example, when I type FilterFacade
and the dot character, I'm presented with a list of supported filters (CreateCarFilter, CreateBikeFilter, ...). So that even if I'm not fully familiar with the project codebase, I can pick one that fits best. With Autofac, IComponentContext
allows me request any component, which doesn't help me find out what relevant components exist, or which components I'm expected to request.
Upvotes: 0