FluentValidation using validator on wrong viewmodel - c#

I'm using FluentValidation for the first time. I had some basic validation working, but then I realized I would need to do some database retrieval for some more complicated validation. That required doing Dependency Injection so I could use the database service, and that leads me to my current state: Stuck. I cannot get this to work.
To simplify things, I'll pretend that my application is dealing with sports leagues and teams, because I figure that's an easier mental model than contracts, invoices, funding sources, vendors, and subcontractors. :-)
So, suppose I have a viewmodel for a sports league. Within that viewmodel there is a collection of viewmodels for the teams that are in that league.
I have a screen to edit a league. That same screen allows changes to some of the information about the teams that are in that league.
LeagueViewModel
The viewmodel for the league contains a List of viewmodels for the teams.
[FluentValidation.Attributes.Validator(typeof(LeagueValidator))]
public class LeagueViewModel
{
public string LeagueName { get; set; }
public DateTime SeasonBeginDate { get; set; }
public DateTime SeasonEndDate { get; set; }
public List<TeamViewModel> TeamViewModels { get; set; }
}
I've created a validator for the LeagueViewModel. Unfortunately, when I edit the league and click the submit button, I get this error message:
InvalidCastException: Unable to cast object of type 'TeamViewModel' to type 'LeagueViewModel'. at FluentValidation.ValidationContext.ToGenericT
Apparently it is attempting to validate the TeamViewModel using the LeagueValidator.
I have gone through many variations trying to figure out how to get this to work. Here's what I have at the moment.
Validator
public class LeagueValidator : AbstractValidator<LeagueViewModel>
{
private readonly ILeagueService _leagueService;
public LeagueValidator(ILeagueService leagueService)
{
_leagueService = leagueService;
RuleFor(x => x.SeasonEndDate)
.NotNull()
.GreaterThan(x => x.SeasonBeginDate)
.WithMessage("Season End Date must be later than Season Begin Date.");
}
}
(The LeagueService bit is in there because in the real code it needs to check against some database values, which it uses the service to retrieve.)
Note that the LeagueValidator doesn't have any validation rules for any fields in the List of TeamViewModels.
League Validator Factory
public class LeagueValidatorFactory : ValidatorFactoryBase
{
private readonly Container _container;
public LeagueValidatorFactory(Container container)
{
_container = container;
}
public override IValidator CreateInstance(Type validatorType)
{
return _container.GetInstance<LeagueValidator>();
}
}
Dependency Injector
We're using SimpleInjector for DI. As part of that existing setup, it is calling a method to register the services. Within that method I've added a call to this:
private static void RegisterValidators(Container container)
{
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
var leagueValidatorProvider =
new FluentValidationModelValidatorProvider(new LeagueValidatorFactory(container));
leagueValidatorProvider.AddImplicitRequiredValidator = false;
ModelValidatorProviders.Providers.Add(leagueValidatorProvider);
container.Register<LeagueValidator>();
}
Questions
How do I get this to work properly?
Why is it trying to use the LeagueValidator to validate the TeamViewModel?
Do I need to have a separate validator and validator factory for every view model?
Even those that don't have any validation rules?
How do I tell it which validator to use for which viewmodel?
I figure I must be misunderstanding something basic.
Edit
Steven's response below got me pointed in the right direction! After I made his suggested changes, I encountered another error. Once I got that fixed, it works! Here are the changes I made to get the code above working properly.
LeagueViewModel
I removed this line, as it isn't necessary.
[FluentValidation.Attributes.Validator(typeof(LeagueValidator))]
LeagueValidatorFactory
I renamed it to "ValidatorFactory", because it turns out there will only be one validator factory, regardless of how many validators I create. I then changed the CreateInstance method to this:
public override IValidator CreateInstance(Type validatorType)
{
if (_container.GetRegistration(validatorType) == null)
{
return null;
}
return (IValidator)_container.GetInstance(validatorType);
}
This no longer explicitly specifies the type of validator to get (which is why only one factory will be needed). To determine whether a validator for the given type is available, it does a call to GetRegistration, returning null if none is found.
This was important! For every viewmodel, it is going to try to find a validator. Without this null check, an InvalidCastException gets thrown.
Dependency Injector
Following Steven's suggestion, I replaced the container.Register line with this:
container.Register(typeof(IValidator<>), new[] { typeof(SimpleInjectorInitializer).Assembly });
That avoids the need to explicitly list each validator every time a new one is added.
And now it all works! Thanks very much for your help, Steven!

I'm unfamiliar with FluentValidation, but it seems your LeagueValidatorFactory is requesting the wrong type from the container, considering it is supplied with the type to validate.
Because of this, I'd expect your validation factory to look something like this:
public class LeagueValidatorFactory : ValidatorFactoryBase
{
private readonly Container _container;
public LeagueValidatorFactory(Container container) =>
_container = container;
public override IValidator CreateInstance(Type validatorType) =>
(IValidator)_container.GetInstance(validatorType);
}
What I can see from the FluentValidator source code, is that the validatorType is a closed-generic version of the IValidator<T> type, with the T being the actual type being validated. This means, that you will have to register the validators by their IValidator<T> interface. For instance:
container.Register<IValidator<LeagueViewModel>, LeagueValidator>();
This Configuration as Code (or explicit-register) model, where you register every validator explicitly using a line of code, might work fine if you have just a few validators, but this will typically result in a Composition Root that has to be updated frequently.
A better model, therefore, is to use Auto-Registration, where you register all IValidator<T> implementations, using reflection. Fortunately, you don't have to implement this yourself; Simple Injector has your back:
var validatorAssemblies = new[] { typeof(LeagueValidator).Assembly };
container.Register(typeof(IValidator<>), validatorAssemblies);
This makes sure that you never have to change your Composition Root when you just added a new validator (in that particular assembly).
With this setup, I see no reason why you should mark your view model with the FluentValidation.Attributes.ValidatorAttribute. If you can, please remove it, as it only causes untight coupling between your view model and the validator.

Related

Fluent Validation and Ioc container: CreateInstance called many times in MVC web application

In the MVC project im working I use Fluent Validation to implement some validation logics and I defined my UnityValidatorFactory as following:
public class UnityValidatorFactory : ValidatorFactoryBase
{
private readonly IUnityContainer _container;
public UnityValidatorFactory(IUnityContainer container)
{
_container = container;
}
public override IValidator CreateInstance(Type validatorType)
{
if (_container.IsRegistered(validatorType))
{
return _container.Resolve(validatorType) as IValidator;
}
return null;
}
}
In global.asax i register my class like this:
var validationFactory = new UnityValidatorFactory(container);
var fluentValidationModelValidatorProvider = new FluentValidationModelValidatorProvider(validationFactory);
I defined my validator for my viewmodel:
public class ServiceRequestViewModelValidator : AbstractValidator<ServiceRequestViewModel>
{
public ServiceRequestViewModelValidator()
{
// many validation rules here...
}
}
I register my validator in unity:
container.RegisterType<IValidator<ServiceRequestViewModel>, ServiceRequestViewModelValidator>();
When i post data to the action with argument of type ServiceRequestViewModel the method CreateInstance is called so many times and the
constructor of ServiceRequestViewModelValidator as well.
Because the validatin rules I implemented are time consuming I don't wont they get executed more then one time. Moreover I don't understand why they are call more than one time.
I later found out that this is how MVC works. In MVC there are many place where MVC needs to get the validator for example it tries to get metadata for each property, and calls into the provider for each one.
Then to fix my problem I created my validators as singleton instances registering the validator in unity with ContainerControlledLifetimeManager
container.RegisterType<IValidator<ServiceRequestViewModel>, ServiceRequestViewModelValidator>(new ContainerControlledLifetimeManager());

EF Model Validation against database

I want to use EF 5 model validation to avoid duplicate values in the database, so I'm using a model class like this:
[Table("MeasureUnits")]
public class MeasureUnit : IValidatableObject
{
public int MeasureUnitId { get; set; }
public string Symbol { get; set; }
public string Name { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
using (MeasureUnitRepository rep = new MeasureUnitRepository())
{
MeasureUnit measureUnit = rep.FindDuplicateBySymbol(this);
if (measureUnit != null)
yield return new ValidationResult(
"There is another unit with this symbol, you can't duplicate it",
new[] { "Symbol" });
}
}
The repository class creates the DbContext, implements IDisposable, has the logic to find the duplicate and it all works just as intended.
However, using the debugger I realized the validation is performed twice for every insert or update, so the repository (and DbContext) gets instantiated and disposed twice also.
Besides that, there is another DbContext living in the controller but just don't find the way to use it inside the model class, other than including the DbContext in the model's constructor, but I feel it's not the right solution.
Is there a better o "right" way to achieve this validation?
Thanks in advance.
When you have to go to the database then you need to use DbContext and DbContext has an Overridable method called ValidateEntity. See this article: Entity Framework Validation.
I put the code I use in another answer here
And more about how I've structured the validation in MVC here.
Also, instantiating a context inside your repository is likely to cause you grief. The repositories will need to share a context. You could treat the context as your unit of work and pass it into the repository in the constructor, or you could wrap the context in your own unit of work and pass that in.
You can use any IOC container available out there like Unity, Ninject, Autofac or StructureMap to inject your repository as a dependency.
This way you would be able to access the same object in the controller, your Validate method or wherever you need to use it.
Some of these IOC(Ninject for sure - look for 'request scope') containers are capable of integrating with ASP.NET MVC so that the dependency(your repository in that case) is created once per request and disposed when the request ends.
Example using Ninject:
You create a globally accessible(the design is up to you) ninject kernel
public static class NinjectKernel
{
public static IKernel Kernel = new StandardKernel();
static NinjectKernel()
{
Kernel.Bind<IMyRepository>().To<MyRepositoryImpl>().InRequestScope();
}
}
and a controller factory for MVC controllers
public class NinjectControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext,
Type controllerType)
{
return controllerType == null ? null : (IController)NinjectKernel.Kernel.Get(controllerType);
}
}
You can then set your controller factory in Global.asax like this
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
and get the repository in your Validate method in a similar way it's done in the Controller factory.

Designing set of rules that use dependencies

I have a service that reads all emails as they get received in a specific mailbox. The issue is that based on what the email contains we have to do one or many actions. I currently have the mess below. I've shortened it quite a bit. The actual application currently has far more corner cases.
var email = new Email { Body = "Some random email body text..." };
if(email.Body.StartsWith("A"))
{
// Requires a dependency on INotifier
Console.WriteLine("Notifying administrator");
}
if (email.Body.StartsWith("B"))
{
// Requires a dependency on IParser and IRepository
Console.WriteLine("Parsing email and adding to database");
}
if (email.Body.EndsWith("C"))
{
// Requires a dependency on ISender and INotifier
Console.WriteLine("Forwarding email and notifying administrator");
}
if (email.Body.EndsWith("C"))
{
// Requires a dependency on INotifier
Console.WriteLine("Ignoring email");
}
Essentially, if a criteria is met then an associating action must get executed using one or more dependencies. These dependencies are something I'd like to inject in the constructor.
I've thought of creating something like this:
public class AdministratorNotififerCriteria : ICriteria
{
private readonly INotifier _notifier;
public AdministratorNotififerCriteria(INotifier notifier)
{
_notifier = notifier;
}
private void Execute()
{
_notifier.Notify();
}
public void CheckSatisfaction(Email email)
{
if(email.Body.StartsWith("A"))
Execute();
}
}
The bottom line is that I wish to make composable commands. So when I add another criteria down the line then all I have to do is inherit from ICriteria (or whatever) and let the application figure it out.
Is there a name for all of this?
I currently have a consumer that resembles this.
public class EmailConsumer
{
private readonly IEnumerable<ICriteria> _criterias;
// Criterias are found and injected with Windsor from all classes inheriting the ICriteria interface
public EmailConsumer(IList<ICriteria> criterias)
{
_criterias = criterias;
}
public void Consume(IList<Email> emails)
{
foreach(var criteria in _criterias)
{
foreach(var email in emails)
{
criteria.CheckSatisfaction(email);
}
}
}
}
Edit
Thanks for the replies, IAbstract and djna. I now understand what the strategy and CoR pattern do and thinking about which is more appropriate is proving that I don't understand enough of my current problem.
The way I understand it is that CoR is greedy and whoever can take responsibility will execute and proceed to the next object to be consumed. On the other hand, there doesn't seem to be anything stopping from looping between strategies that says "Hey! I can consume this request properly so don't worry about it".
This seems like a variation of Chain of responsibility with possibly some extra logic for dealing with non-exclusive cases - what do you intend should happen if the Body starts with "A" and ends with "C"?
One idea in Chain of Resposibility is that there's no need for a huge dispatching if/else chain. Instead you just offer the email to some ICriteria implementatio, and they have responsibility either to process or pass on to the next candidate.
#djna suggests a variation of the CoR pattern. I don't completely disagree. It seems more like this example of the Strategy Pattern.

Property Injection into an Action Filter

I'm trying to get Property Injection working on a Custom Action Filter Attribute. It is working as it is supposed to, however, I'd like to use DI on the Property itself. My filter looks like this
[AttributeUsage(AttributeTargets.Class)]
public sealed class HeaderFilterAttribute : ActionFilterAttribute
{
public IMarketService MarketService
{ get; set; }
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var view = (ViewResultBase)filterContext.Result;
if (view != null)
{
BaseViewModel viewModel = view.ViewData.Model as BaseViewModel;
if (viewModel != null)
viewModel.Header = GetHeaderScript();
}
base.OnActionExecuted(filterContext);
}
private string GetHeaderScript()
{
//Use MarketService here and return header script
return "script";
}
}
This is how I'm configuring the property using StructureMap inside my BootStrapper class.
//HeaderFilterAttribute
IMarketRepository marketRepository = new SqlMarketRepository();
IMarketService marketService = new MarketService(marketRepository);
ObjectFactory.Container.Configure(r => r.ForConcreteType<HeaderFilterAttribute>().
Configure.WithProperty("MarketService").
EqualTo(marketService));
My problem is I do not have access to SqlMarketRepository since all my concrete types are injected via DI and I really don't want to use concrete types in my bootstrapper. So the ultimate question now is, how do I inject MarketService into the Filter attribute without resorting to the above? :)
In your ObjectFactory.Initialize() call, add the following line:
SetAllProperties(x => x.OfType<IMarketService>());
That will inject the configured IMarketService instance into any property of type IMarketService, on any object retrieved from the container.
I think you need a custom action invoker implementation that will resolve the filters. You can dig a Windsor sample out of my company's implementation (about 1/2 way down). There should be several more available online. I know I've seen some on this site.
PS. I noticed you're using a base view model to populate a header. I'd recommend using the ViewData[] collection with a static key instead of inheritance in your view model. :)

Database injection into a validation attribute with ASP MVC and Castle Windsor

I need some help - I am trying to use a custom validation attribute in an ASP.NET MVC web project that needs to make a database call.
I have windsor successfully working for the controllers and the IRepository interface is injected normally. The problem arrises when I need to inject the repository into the attribute class.
The attribute class has the following code:
public class ValidateUniqueUrlNodeAttribute : AbstractValidationAttribute
{
private readonly string message;
private readonly IArticleRepository articleRepository;
public ValidateUniqueUrlNodeAttribute(string message)
{
this.message = message;
}
public ValidateUniqueUrlNodeAttribute(string message, IArticleRepository articleRepository):this(message)
{
this.articleRepository = articleRepository;
}
public override IValidator Build()
{
var validator = new UniqueUrlNodeValidator(articleRepository) { ErrorMessage = message };
ConfigureValidatorMessage(validator);
return validator;
}
My problem is that I cannot seem to make Windsor intercept the contruction of the attribute to pass in the IArticleRepository
The current code in my global.asax file is as follows:
container = new WindsorContainer();
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(Container));
container
.RegisterControllers(Assembly.GetExecutingAssembly())
.AddComponent<IArticleRepository, ArticleRepository>()
.AddComponent<ValidateUniqueUrlNodeAttribute>();
Any help would be greatly appreciated.
AFAIK no dependency injection container can directly manage an attribute, since it's instantiated by the runtime and there's no way to intercept that.
However, they can cheat by either:
Using a static gateway to the container (example), or
Using a "BuildUp" feature that injects whatever dependencies are found within an already-constructed object. This is called BuildUp in Unity or InjectProperties in Autofac.
Windsor doesn't support #2 (ref1, ref2), so you can either:
Try one of the hacks to make Windsor support #2 (hack1, hack2)
Use a static gateway
Implement your own IValidatorBuilder and make it use Windsor to create validators. I'm sure this is implemented somewhere but I can't find it right now...
Don't know if this helps, but I subclassed ValidationAttribute to expose a Resolve<T>() method like so:
public abstract class IocValidationAttribute : ValidationAttribute
{
protected T Resolve<T>()
{
return IocHelper.Container().Resolve<T>();
}
}
Then it can be used in any custom ValidatorAttribute that needs to hit a database:
public class UniqueEmailAttribute : IocValidationAttribute
{
public override bool IsValid(object value)
{
ICustomerRepository customerRepository = Resolve<ICustomerRepository>();
return customerRepository.FindByEmail(value.ToString()) == null;
}
}
I think it's a variation of the 'Static Gateway' approach mentioned by Mauricio Scheffer. I don't know if this is a good design or not. I'm not a huge fan of it, I'd rather the dependency was injected more 'elegantly', though I can't use constructor injection obviously, I'd like to use Property injection but can't work out a way to hook into the ASP.NET MVC framework code to do this (I've even pored though the MVC2 source code).
I was able to wire it up [using Autofac as it happens, but it's just constructor injection via the ASP.NET MVC DependencyResolver] in this answer, enabling one to write:
class MyModel
{
...
[Required, StringLength(42)]
[ValidatorService(typeof(MyDiDependentValidator), ErrorMessage = "It's simply unacceptable")]
public string MyProperty { get; set; }
....
}
public class MyDiDependentValidator : Validator<MyModel>
{
readonly IUnitOfWork _iLoveWrappingStuff;
public MyDiDependentValidator(IUnitOfWork iLoveWrappingStuff)
{
_iLoveWrappingStuff = iLoveWrappingStuff;
}
protected override bool IsValid(MyModel instance, object value)
{
var attempted = (string)value;
return _iLoveWrappingStuff.SaysCanHazCheez(instance, attempted);
}
}
With some helper classes (look over there), you wire it up e.g. in ASP.NET MVC like so in the Global.asax :-
DataAnnotationsModelValidatorProvider.RegisterAdapterFactory(
typeof(ValidatorServiceAttribute),
(metadata, context, attribute) =>
new DataAnnotationsModelValidatorEx(metadata, context, attribute, true));
Hmm.
Can you test the effect of removing the (string message) ctor, and see if that at least forces Castle to use the ctor with the Repostiory ?
Otherwise we call AddComponent(name, type, type). Other than that it really should work...
Also does this hint at my first idea ? How do I use Windsor to inject dependencies into ActionFilterAttributes

Categories