2

I have the following on an ASP.NET Core application Startup:

services.AddDbContext<Context>(x => x.UseSqlServer(connectionString));

services.AddFluentValidation(x => x.RegisterValidatorsFromAssemblyContaining<Startup>());

When I inject Entity Framework context on a FluentValidation validator:

public class TestModelValidator : AbstractValidator<TestModel> {
  public TestModelValidator(Context context) {  
  }
}

I get the following error:

ObjectDisposedException: Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur is you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Object name: Context

What am I missing?

Miguel Moura
  • 36,732
  • 85
  • 259
  • 481
  • Does `AddFluentValidation` register as singleton? You can't inject DbContext in singletons, because the default settings is that `DbContext` is registered as scoped service and get disposed after each request (to avoid memory leaks by DbContext tracking the states) – Tseng Jul 29 '16 at 22:53
  • Yes, fluent validation adds as singletons. But I also tried injecting a Func and I get the same error. Should I? – Miguel Moura Jul 29 '16 at 22:56
  • How did you registered `Func`? A factory method should work actually work, if registered correctly – Tseng Jul 29 '16 at 22:57
  • I didn't ... I mean when registering the Context wouldn't work with Func? I am using AutoFac. But I thought registering the Context the usual Asp.Net Core would do it – Miguel Moura Jul 29 '16 at 23:01

1 Answers1

1

As mentioned in comments, validators instantiated as singletones by default, and I strongly recommend you not to change validators lifetime due to perfomance reasons — they are very expensive to instantiate.

I prefer to instantiate lightweight Context object on demand inside PredicateValidator (aka Must) expression body — this approach resolve problem of lifetime disparity.

Example with ServiceLocator pattern:

public class MyValidator: AbstractValidator
{
    public MyValidator()
    {
        RuleFor(x => x.Email).Must(email => IsUnique(email)).WithMessage("email must be unique");
    }

    private IsUnique(string email)
    {
        var context = !ServiceLocator.Instance.Resolve<Context>();
        return context.Users.Any(x => x.Email == email);
    }
}

This topic might be helpful for implementation of service locator with AutoFac.

Community
  • 1
  • 1
David Levin
  • 6,573
  • 5
  • 48
  • 80