1

I'm trying to setup a custom model validator provider using FluentValidation. Everything works until i try to inject a business layer manager into the validator's constructor to run some business logic.

public class Repository : IRepository
{
    public Repository(IDbConnection)
    {
    }
}

public class Manager : IManager
{
    public Manager(IRepository)
    {
    }
}

public AutofacValidatorFactory : ValidatorFactoryBase
{
}

public MyModelValidator : AbstractValidator<MyModel>
{
    public MyModelValidator(IManager) { }
}

I wire everything up like so:

builder.Register(c => new SqlConnection(ConfigurationManager.ConnectionStrings["MyCS"].ConnectionString))
               .As<IDbConnection>().InstancePerApiRequest();

builder.RegisterType<Repository>()
               .As<IRepository>()
               .InstancePerDependency();

builder.RegisterType<Manager>()
               .As<IManager>()
               .InstancePerDependency();

builder.RegisterType<ValidatorFactory>()
               .As<IValidatorFactory>()
               .InstancePerLifetimeScope();

        builder.RegisterType<FluentValidation.Mvc.WebApi.FluentValidationModelValidatorProvider>()
               .As<ModelValidatorProvider>()
               .InstancePerLifetimeScope();

        AssemblyScanner.FindValidatorsInAssembly(assembly)
                       .ForEach(
                           result =>
                           Builder.RegisterType(result.ValidatorType).As(result.InterfaceType).InstancePerApiRequest());

Finally, i add the FluentValidator Model Provider like so:

// _validatorProvider is injected as per Autofac config above.    
GlobalConfiguration.Configuration.Services.Add(typeof(ModelValidatorProvider), _validatorProvider);

The issue is occurring when my validator factory tries to spin up a validator instance. At which point i get the following exception:

"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 think the issue has something to do with the way Manager & Repository is configured in Autofac but i don't know what i'm missing.

EDIT: This issue is occurring in a Web API project.

Sergey Akopov
  • 1,130
  • 1
  • 11
  • 25

1 Answers1

2

Without seeing more of your code I cannot answer your direct question, however I can answer what this exception generally means

Autofac supports nested lifetime scopes (i.e. child containers). The main container is actually just the root lifetime scope. Each lifetime scope can be thought of as a unit of work. You create the lifetime scope, resolve the instances required to perform that task, then dispose the lifetime scope. Anything created by the lifetime scope is then disposed.

Registering as SingleInstance means that single instance is resolved and stored by the root scope. Using InstancePerLifetimeScope will recreate each instance per scope it was resolved from, so you can end up with an instance in the root scope and your child scope. InstancePerMatchingLifetimeScope allows you to register a type so that it is shared between all the child containers of that specific branch of the tree. These types can never exist or be accessed by anything in the root scope. InstancePerApiRequest is the same as InstancePerMatchingLifetimeScope(“AutofacWebRequest”).

In your application each request will be a child autofac scope. Something registered to the child scope (i.e. your IDBConnection) can use anything else in the same scope (registered as InstancePerLifetimeScope) and anything in the parent scope (registered as SingleInstance) however there is a potential problem here. Something registered to the parent scope (for example as SingleInstance in the root container) cannot access anything registered as InstancePerMatchingLifetimeScope in the child scope as the parent scope doesn’t have access to instances in child scopes.

This is what you have most likely done – registered something as a SingleInstance which has a dependency on something registered to a Matching Lifetime scope.