3
votes

New to AutoFac as was recently using SimpleInjector, but since i have upgraded to vNext/.NET5, AutoFac seems to be updated to work with it, so using AutoFac instead.

All i want to do is to make sure that my DbContext is created on each Request. I can do this by using .InstancePerRequest() but when i do this (which i have added to all my code), i seem to get the error message

Autofac.Core.DependencyResolutionException 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.

I believe this is saying that something is not being requested as per-HTTP request, so nothing will? Is that right? If so, kinda seems a bit stupid. I dont care if my services and validators are only created once, but i need the DbContext created on each request, as when multiple requests are connected to my WebApi, i keep getting an error saying

A second operation started on this context before a previous asynchronous operation completed.

However, if i execute these calls one after another myself, then they all work fine.

I am using EntityFramework 6.1, and not EF7, because EF7 is far from complete yet.

I have my AutoFac Module, like so

public class SetupModule : Autofac.Module
{
    protected override void Load(ContainerBuilder builder)
    {
        // IDataContext
        builder.Register((c) =>
            {
                var appEnv = c.Resolve<IApplicationEnvironment>();
                var configBuilder = new ConfigurationBuilder(appEnv.ApplicationBasePath)
                    .AddJsonFile("config.json");
                var configuration = configBuilder.Build();

                return new DataContext(configuration["Data:MyConnection:ConnectionString"]);
            })
            .As<IDataContext>()
            .InstancePerRequest();

        // Validators
        builder.RegisterAssemblyTypes(System.Reflection.Assembly.GetAssembly(typeof(IValidator)))
            .Where(t => typeof(IValidator).IsAssignableFrom(t))
            .AsImplementedInterfaces()
            .InstancePerRequest();

        // Services
        builder.RegisterType<ContentService>().As<IContentService>().InstancePerRequest();

    }
}

My DataContext is like a standard DbContext class with constructor, just taking the connectionString

public DataContext : IDataContext {
    public DataContext(string connectionString)
        : base(connectionString)
        {

        }
}

And in my Startup.cs file i register this using this

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    // Create the Autofac container builder.
    var builder = new ContainerBuilder();
    builder.RegisterModule(new AutoFac.SetupModule());
    builder.Populate(services);

    // Build the container.
    var container = builder.Build();

    // Resolve and return the service provider.
    return container.Resolve<IServiceProvider>();
}

Can someone tell me exactly what am i missing? Is it something to do with how i am creating my DataContext, as need to do this to be able to get the connectionString from the config.json file.

Thanks in advance

NOTE: If i change to .InstancePerDependency() my error stops, but i do not think this is what i want on all objects

UPDATE Here is the stacktrace

at Autofac.Core.Lifetime.MatchingScopeLifetime.FindScope(ISharingLifetimeScope mostNestedVisibleScope) 
at Autofac.Core.Resolving.InstanceLookup..ctor(IComponentRegistration registration, IResolveOperation context, ISharingLifetimeScope mostNestedVisibleScope, IEnumerable<Parameter> parameters)
at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable<Parameter> parameters)
at Autofac.Core.Resolving.ResolveOperation.ResolveComponent(IComponentRegistration registration, IEnumerable<Parameter> parameters) 
at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable<Parameter> parameters) 
at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration, IEnumerable<Parameter> parameters) 
at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable<Parameter> parameters, Object& instance) 
at Autofac.ResolutionExtensions.ResolveOptionalService(IComponentContext context, Service service, IEnumerable<Parameter> parameters) 
at Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, Type serviceType, IEnumerable<Parameter> parameters) 
at Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, Type serviceType) 
at Autofac.Framework.DependencyInjection.AutofacServiceProvider.GetService(Type serviceType) 
at Microsoft.Framework.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired) 
.lambda_method(Closure , IServiceProvider , Object[] ) 
at Microsoft.AspNet.Mvc.DefaultTypeActivatorCache.CreateInstance<TInstance>(IServiceProvider serviceProvider, Type implementationType) 
at Microsoft.AspNet.Mvc.DefaultControllerActivator.Create(ActionContext actionContext, Type controllerType) 
at Microsoft.AspNet.Mvc.DefaultControllerFactory.CreateController(ActionContext actionContext) 
at Microsoft.AspNet.Mvc.Core.ControllerActionInvoker.CreateInstance() 
at Microsoft.AspNet.Mvc.Core.FilterActionInvoker.<InvokeAllActionFiltersAsync>d__49.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Mvc.Core.FilterActionInvoker.<InvokeExceptionFilterAsync>d__48.MoveNext() 
--- exception rethrown --- 
at Microsoft.AspNet.Mvc.Core.FilterActionInvoker.<InvokeAsync>d__41.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Mvc.MvcRouteHandler.<InvokeActionAsync>d__7.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Mvc.MvcRouteHandler.<RouteAsync>d__6.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Mvc.Routing.InnerAttributeRoute.<RouteAsync>d__10.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Routing.RouteCollection.<RouteAsync>d__9.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Builder.RouterMiddleware.<Invoke>d__4.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Hosting.Internal.RequestServicesContainerMiddleware.<Invoke>d__3.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Hosting.Internal.HostingEngine.<>c__DisplayClass29_0.<<Start>b__0>d.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Loader.IIS.RuntimeHttpApplication.<ProcessRequestAsyncImpl>d__13.MoveNext() 
--- exception rethrown --- 
at Microsoft.AspNet.Loader.IIS.RuntimeHttpApplication.<ProcessRequestAsyncImpl>d__13.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Loader.IIS.HttpApplicationBase.<InvokeProcessRequestAsyncImpl>d__9.MoveNext()
2
I can't see where in your code you are using InstancePerRequestYacoub Massad
What are the types that have a dependency on IDataContext? Can you show them?Yacoub Massad
Updated. Sorry i was playing woth the code and had Lifetime instead of InstancePerRequest. Also added IDataContext to DataContext classGillardo
The error means that Autofac try to resolve a component that need another component which required a request scope. Could we have a stack trace of the error ?Cyril Durand

2 Answers

0
votes

It seems that one or both of two things are happening:

  • Autofac is not properly integrated with ASP.NET and has not started a new lifetime scope tagged AutofacWebRequest.
  • You are resolving a component that has been registered as InstancePerRequest() in a lifetime scope whose ancestry does not include a lifetime scope tagged AutofacWebRequest.

Looking at the stack trace, it seems that the first case is more likely than the second, because the exception is occurring in the construction of a controller.

0
votes

the short answer is you cant have a longer living thing depend on a short lived thing

example: single depends on instance per request is bad

so the typical default is instance per dependency (transient, so every time you need one a new one is created).

if you have A that is instance per request and B that is singleton

and then A depends on B, no problem but if B depends on A you run into issues as B would never gets re-created but depends on A that is going to get re-created every scope.

other libs sometimes let you make this mistake and find it on your own (very painful)

seems like AutoFact is doing a better job at letting you know something is wrong with scope hierarchy.