Fluent Validation and Structure Map Problem.

Sep 11, 2010 at 7:09 PM

Hello,

I have the following validator:

  public class UserCreateModelValidator : AbstractValidator<UserCreateModel> {

    private IUserService _userService;

    public UserCreateModelValidator(IUserService userService) {

      _userService = userService;

      CascadeMode = CascadeMode.StopOnFirstFailure;

      RuleFor(o => o.Username).Must(username => _userService.FindByUsername(username) == null).WithMessage("Username already taken");      
        
    }

  } // UserCreateValidator

When I try to create a username I get the following error on my repository which is used in UserService:

  The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.

On my Application_EndRequest I have the following to automatic save the context:

      ObjectFactory.GetInstance<Domain.IContext>().Save();

      ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();

I am using Structure Map for IOC and in my Application_Star I have the following:

      ValidatorFactory validatorFactory = new ValidatorFactory();
      ModelValidatorProviders.Providers.Add(new FluentValidationModelValidatorProvider(validatorFactory));
      DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;

I think the problem might be when I am realeasing and disposing the Http Scroped Objects.

But shouldn't I do this?

Maybe something wrong in my Fluent Validation Configuration?

Thank You,

Miguel

 

Coordinator
Sep 11, 2010 at 7:15 PM

This isn't really an issue with FluentValidation but is a general issue related to the use of an IoC container. If a particular component is scoped per http request then anything that depends on it will have to have the same lifetime. In this case, if your ObjectContext is scoped per http request then both your UserService and UserCreateModelValidator will also need to be registered with http request scope as they depend on the current ObjectContext instance.

Jeremy

 

Sep 11, 2010 at 7:36 PM
Edited Sep 11, 2010 at 7:42 PM

Yes, 

I have all repositories, services and context registered as http request scoped:

 

For<IRoleRepository>().HttpContextScoped().Use<RoleRepository>();
   For<IUserRepository>().HttpContextScoped().Use<UserRepository>();

For<IRoleService>().HttpContextScoped().Use<RoleService>();
For<IUserService>().HttpContextScoped().Use<UserService>();      

For<IContext>().HttpContextScoped().Use(() => new Context());

 

Is there any reason for not having the validators registered with http request scope and having them as singleton?

Thank You,

Miguel

 

Coordinator
Sep 11, 2010 at 7:42 PM

You could use the AssemblyScanner to register all the validators in a particular assembly, see http://www.jeremyskinner.co.uk/2010/02/22/using-fluentvalidation-with-an-ioc-container/

Typically validators should be registered as singleton-scoped because they're expensive to create (expression tree compilation is slow). Scoping them per context could potentially lead to performance issues. An alternative approach would be to not inject the IUserService directly into your validator, but rather to inject a factory that can lazily retrieve the current UserService instance. This way the validator could remain as singleton scoped.

Jeremy

Sep 11, 2010 at 7:46 PM

I am going to do just that.

Thank You,

Miguel

 

 

Sep 11, 2010 at 11:31 PM

Jeremy,

Do you have any article about using and injecting a factory into a Validator using Structure Map?

Thank You,

Miguel

Sep 12, 2010 at 12:00 AM

Oops, I just found a solution. I am passing the IContainer of StructureMap to the Validator.

It is working now and the Validators are Singleton scoped and using the AssemblyScanner.

Thank You,

Miguel

Coordinator
Sep 12, 2010 at 10:08 AM

Probably not a good idea to pass the container directly to your validator, as your validator then has a dependency on StructureMap. A better solution would probably be to inject a small, dedicated factory (or even a delegate). 

Jeremy

 

Sep 12, 2010 at 11:22 AM

Could you provide a simple example? I confess I am a little bit lost.

I ended up injecting the container everywhere, including the controllers and services, which works but I think it might be a good idea.

Thank You,

Miguel

Coordinator
Sep 12, 2010 at 11:52 AM

I would recommend against injecting the container into controllers and services - the point of using a container is that it injects your components in an unobtrusive manner without needing to compromise on your design. By injecting the container directly, you're tightly coupling your application to that particular container. The only place the container should really be used is to construct your root level objects (in an MVC app, this is the controller, so typically the only place the container should be used is by the Controller Factory). If you need lazy instantiation, then you can use a Func<T> instead. Modern versions of StructureMap (2.6.1) can treat this as a factory that will call back in to the container to resolve the component.

Using your UserCreateModelValidator as an example, rather than taking an IUserService, you instead take a Func<IUserService>. This way, the validator is not holding onto a reference of IUserService. Whenever you need to access the IUserService, you invoke the delegate which will call back to the container to get the appropriate instance (in this case, out of http request storage). For the next request, invoking the same delegate will result in the new IUserService being returned.

public class UserCreateModelValidator : AbstractValidator<UserCreateModel> {
	readonly Func<IUserService> _userServiceFactory;

	public UserCreateModelValidator(Func<IUserService> userServiceFactory) {
		_userServiceFactory = userServiceFactory;

		RuleFor(x => x.Username).Must(NotAlreadyExist).WithMessage("Username already taken");
	}

	bool NotAlreadyExist(string username) {
		var userService = _userServiceFactory();
		return userService.FindByUsername(username) == null;
	}
}

I split the 'Must' predicate into a separate method (NotAlreadyExist) to make it easier to read, although it could be moved in line with a lambda.

If you need more help with StructureMap's lazy resolution I'd suggest asking on the StructureMap mailing list (http://groups.google.com/group/structuremap-users/)  

Jeremy

Sep 12, 2010 at 2:37 PM

Thank You. I have a post on StructureMap mailing list.

Keeping the discussion here only about FV. Do you advice to access services from the validator?

The other option I see, that avoids the need for user service inside the validator would be:

    public virtual ActionResult Create(UserCreateModel model) { 

      if (ModelState.IsValid) {  // This would use the validator 

        try { 
          _userService.Create(Mapper.Map<UserCreateModel, 
User>(model)); 
        } catch { 
          // Add error to model state and return the model. 
        } 

      } else { 
        return View(model); 
      } 

    } // Create 

So I could have my UserService.Create() to fire an exception if the username already exists. 

In this approach the "problem" is the validation is made in two steps.

The username is only checked, and error message displayed if that's the case, if all the other fields are valid.

Is there any other approach for theses cases? 

How is usually done when using FV and such a case appears?

Thanks,

Miguel

Coordinator
Sep 12, 2010 at 2:52 PM

I don't see anything wrong with injecting a service into a validator. It seems like a perfectly sensible approach as it keeps all the validation logic in one place.

Jeremy

Jun 10, 2013 at 10:16 PM
I'm confused, how does the code from http://www.jeremyskinner.co.uk/2010/02/22/using-fluentvalidation-with-an-ioc-container/
  AssemblyScanner.FindValidatorsInAssemblyContaining<MyValidator>()
      .ForEach(result => {
           For(result.InterfaceType)
              .Singleton()
              .Use(result.ValidatorType);
      });
Scan and find all validators? Isn't that just getting MyValidator? Or will that get all IValidator<T>?
Coordinator
Jun 10, 2013 at 10:28 PM
That will get all IValidators. The assembly scanner finds all types in the specified assembly that implement IValidator<T>. If you're interested in knowing how this works, take a look at the code for AssemblyScanner.cs in the FluentValidation source.
Jun 11, 2013 at 8:00 PM
I did, but it just doesn't seem clear to me. It looks like it will only find types of MyValidator, not IValidator<T>. So I did not try that code before looking at the source. I did try
 AssemblyScanner.FindValidatorsInAssembly(Assembly.GetExecutingAssembly())
                .ForEach(result => For(result.InterfaceType)
                                        .Singleton()
                                        .Use(result.ValidatorType));
But that did not work. No validators fire. But if the one with "MyValidator" really means IValidator<T> I'll try that too. Initially it looks confusing.

Thanks.