Here's my project: ASP.NET Core Web API with Autofac.
I got the Autofac working fine: it injects all the services/classes I registered automatically. It's so beautiful!
I need to take it a step further, and looking to resolve class
s using their Name
, in a GET
method on one of the API controller.
This is my registration:
builder.RegisterAssemblyTypes(automationAssembly)
.Where(t => t.IsSubclassOf(typeof(AbstractParentClass)))
.Named<AbstractParentClass>(t => t.Name);
And this is where I am stuck, trying to resolve
the named class
[HttpGet("{className}")]
public string Get(string className)
{
Container.ResolveNamed("className", "AbstractParentClass") // => not sure how to get `Container` here
return "value " + className;
}
I somehow need to get access to Autofac's Container
, but not sure how to get it in the ASP.NET Core Web API setup.
Any ideas anyone? TIA
There are a couple ways to do what you need to do.
The first, and recommended, way, is to not use the Autofac relationship types to get what you need and not get the current lifetime scope at all.
public class MyController : ControllerBase
{
private IIndex<string, Lazy<AbstractParentClass>> _classes;
public MyController(IIndex<string, Lazy<AbstractParentClass>> classes)
{
this._classes = classes;
}
[HttpGet("{name}")]
public string Get(string name)
{
// Two steps here - get the Lazy<T> out of the IIndex<X, B>
// then resolve the value from the Lazy<T>.
var resolved = this._classes[name].Value;
return resolved.DoSomething();
}
}
You can combine relationships, and that's what you see here. You don't actually want to resolve every single instance of the registered types, you want to defer that - so Lazy<T>
to defer it. Then you want to inspect the set of them and pick one by name - so IIndex<X, B>
.
By doing that, you don't have to do service location at all.
However, if you don't like that and you're into service location, ControllerBase
offers a bunch of helpful extensions to access the current request context.
public class MyController : ControllerBase
{
[HttpGet("{name}")]
public string Get(string name)
{
var scope = this.HttpContext.RequestServices.GetRequiredService<ILifetimeScope>();
var resolved = scope.ResolveNamed<AbstractBaseClass>(name);
return resolved.DoSomething();
}
}
Of course, you can make that even simpler by just injecting the current request lifetime scope.
public class MyController : ControllerBase
{
private ILifetimeScope _scope;
public MyController(ILifetimeScope scope)
{
this._scope = scope;
}
[HttpGet("{name}")]
public string Get(string name)
{
var resolved = this._scope.ResolveNamed<AbstractBaseClass>(name);
return resolved.DoSomething();
}
}
But, again, if it was me I'd probably use the first option with IIndex<X, Lazy<B>>
so I wouldn't have to do service location anywhere.