I'm trying to resolve a dependency in the StartUp
class of an ASP.Net WebApi 2 project. Autofac is used to configure the dependency injection. The scenario is as follows:
StuffFactory
and the list the StuffModel
.The problem now is that all of this needs to be registered as InstancePerRequest
. This throws an InvalidOperatonException
, which sounds reasonable because the Request lifetime scope cannot be accessed in the StartUp
?
No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.
The code where the allowed stuff is registered in the container:
private IContainer RegisterAllowedStuff(IContainer container)
{
var builder = new ContainerBuilder();
builder.Register(x => GetAllowedStuffForUser(container))
.As<StuffModel>()
.InstancePerRequest();
builder.Update(container);
return container;
}
private static StuffModel GetAllowedStuffForUser(IContainer container)
{
var stuffFactory = container.Resolve<IStuffFactory>();
return stuffFactory.CreateStuffModel(Helper.GetParsedUserName());
}
I am kind of stuck on how to advance from here. Is there an easy solution for the Autofac problem that I am completely overseeing? Does someone maybe have a better idea of how I could implement this? Thanks in advance!
You should not have any business logic in your startup class. Autofac allows you to register lambda method which will be called at resolve time. At this time, a HttpRequest
is available, so you can register theses lambda as InstancePerRequest
.
In your case, if you want to register a StuffModel
as InstancePerRequest
you can do it like this :
builder.RegisterType<ConcreteStuffFactory>()
.As<IStuffFactory>();
builder.Register(c => c.Resolve<IStuffFactory>()
.CreateStuffModel(Helper.GetParsedUserName()))
.As<IStuffModel>()
.InstancePerRequest();
By the way, I would also not used an Helper class which looks like an anti-pattern, you can create a service to get the user name of the current user, for exemple IUserContextProvider
. You can also add a IUserContextProvider
dependency on the ConcreteStuffFactory
public class ConcreteStuffFactory
{
public ConcreteStuffFactory(IUserContextProvider userContextProvider)
{
this._userContextProvider = userContextProvider;
}
private readonly IUserContextProvider _userContextProvider;
public IStuffModel CreateStuffModel()
{
String userName = this._userContextProvider.UserName;
// do things with userName
}
}
and the registration :
builder.RegisterType<ConcreteStuffFactory>()
.As<IStuffFactory>();
builder.RegisterType<HttpContextUserContextProvider>()
.As<IUserContextProvider>()
.InstancePerRequest();
builder.Register(c => c.Resolve<IStuffFactory>().CreateStuffModel())
.As<IStuffModel>()
.InstancePerRequest();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With