问题
I have ASP.NET MVC application where I registered a component with an InstancePerHttpRequest
scope.
builder.RegisterType<Adapter>().As<IAdapter>().InstancePerHttpRequest();
then I have an async piece of code where I'm resolving the Adapter component.
The following code is simplified
Task<HttpResponseMessage> t = Request.Content.ReadAsMultipartAsync(provider).ContinueWith(t =>
// IHandleCommand<T> takes an IAdapter as contructor argument
var h = DependencyResolver.Current.GetServices<IHandleCommand<T>>();
);
The code above is throwing an exception: The request lifetime scope cannot be created because the HttpContext is not available.
So I did some research on the subject and found this answer https://stackoverflow.com/a/8663021/1003222
Then I adjusted the resolving code to this
using (var c= AutofacDependencyResolver.Current.ApplicationContainer.BeginLifetimeScope(x => x.RegisterType<DataAccessAdapter>().As<IDataAccessAdapter>).InstancePerLifetimeScope()))
{
var h = DependencyResolver.Current.GetServices<IHandleCommand<T>>();
}
But the exception stayed the same. The request lifetime scope cannot be created because the HttpContext is not available.
Am I missing something ?
回答1:
you can try something like this:
using (var c= AutofacDependencyResolver.Current
.ApplicationContainer
.BeginLifetimeScope("AutofacWebRequest"))
{
var h = DependencyResolver.Current.GetServices<IHandleCommand<T>>();
}
回答2:
Autofac tries to resolve the container from the MVC Dependency Resolver, If you have a async operation the httpContext won't be available so DependencyResolver won't be available either.
One option in to make the container available in a static variable or a proper instance, and create a context scope for this operation.
public static IContainer Container
once you have the builder setup, copy the container
public class ContainerConfig
{
public static IContainer Container;
public static void RegisterComponents()
{
var builder = new ContainerBuilder();
builder.RegisterInstance(new Svc()).As<ISvc>();
Container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(Container ));
}
}
then when resolving use the static container config to create the instance you need.
using (var scope = ContainerConfig.Container.BeginLifetimeScope())
{
result = ContainerConfig.Container.Resolve<T>();
}
hope it helps
回答3:
If you do not have access to System.Web.Http you can´t use DependencyResolver.Current. You need to store your container and Resolve the dependency from it:
//On Startup Class
public static IContainer Container { get; private set; }
public void Configuration(IAppBuilder app)
{
...
var builder = new ContainerBuilder();
builder.RegisterModule([yourmodules]);
...
var container = builder.Build();
Container = container;
}
Then, when you need your instance:
using (var scope = Container.BeginLifetimeScope())
{
YourInterfaceImpl client = Container.Resolve<YourInterface>();
...
}
Hope this help!
回答4:
In my case I was instantiating all types on WebAPI startup, to catch any failures as early as possible. At that point, there's no request, so with a type registered as InstancePerRequest
I was getting this error:
No scope with a tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested.`
Based on @KozhevnikovDmitry's answer, this is how I got it working:
using (var scope = container.BeginLifetimeScope("AutofacWebRequest"))
{
foreach (Service item in container.ComponentRegistry.Registrations.SelectMany(x => x.Services))
{
Type type = item is TypedService ts ? ts.ServiceType
: item is KeyedService ks ? ks.ServiceType
: throw new Exception($"Unknown type `{item.Description}`");
try
{
scope.Resolve(type);
}
catch (Exception ex)
{
_log.Debug($"Error instantiating type `{type.FullName}`", ex);
throw;
}
}
}
来源:https://stackoverflow.com/questions/15050207/autofac-scope-lifetime-issue