Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unobtrusive Validation Keeps breaking in MVC4

I have been having a wierd issue that is driving me absolutely crazy.

It started with the following error out of the blue after it had been working great:

Validation type names in unobtrusive client validation rules must be unique. The following     
validation type was seen more than once: required

This error first started on one of my controllers in Area/Admin/WebSites. But as soon as my auth cookie expired I got it on my Login page as well on the EditFor(m=>m.UserName) line. I combed through my code looking for duplicate Required attribute anywhere on any model that might be remotely named the same to no avail.

I even went into my LoginViewModel, removed the [Required] From UserName. The error moved to the EditFor(m=>m.Password). I removed the Required from Password as well, and the error moved the RememberMe line but there was no Required attribute on that member at all even. In fact I have nothing else even remotely named RememberMe in any other class anywhere.

Okay, well I gave up and started rebuilding the webSite project from scratch (not the rest of the solution) and still ended up with the same thing.

Out of desperation, I rebuild the entire solution from scratch, only copying the *.cs files in and manually reloading all the references thinking there was a duplicate reference somewhere.

Once I got to the point of building the MVC4 project once again I did it in stages to see if I could figure what was happening. It was doing fine, loading up and I could log in, etc, until I started adding Areas. At first I just copied the Areas folder directly into the project (all the namespace names are the same, so this should have been fine). But sure enough I started getting this error right way.

Okay, so I started deleting controllers in reverse order of my creating them originally. The site never returned to normal until I had deleted the Areas folder completely.

Testing this, as soon as I created an Areas folder in the project, it would break. Same thing if I used the GUI to create the new Area.

Okay, back to the drawing board. Recreated the MVC4 project from scratch, this time outside of the solution and only pulled in the 2 critical NuGet packages critical to my solution at this point: Ninject.MVC3 and Mvc3ControlsKit (the one from nuget which is for both 3 & 4). Okay everything finally starts working great. At this point, my Jquery is version 1.7.2 with the default Jquery UI that comes with MVC4.

At some point, I ran into a problem with the jquery dialog not closing so I installed JQuery 1.8.2 and the latest JQuery UI from NuGet. Everything worked fine until I went to add a completely blank Controller in my Admin Area and this error popped up again.

Okay, back to the drawing board again... I rebuilt it in stages, testing at each point. This time not installing the latest JQuery goodies. Everything starts working fine again. Added a new controller, then two. Okay, made a valid copy of this version and set it aside. Updated Jquery and Jquery UI to latest versions. Add a new controller in the area and it still continues to work to my complete frustration.

My Entities are all using Fluent API to configure my entities with no DataAnnotatian Attributes at all. Any ideas? I keep waiting for it to break again.

EDIT:

Here is some more information I just figured out. The error is occuring on this line of code in my LogIn Partial View. My model is

public class LoginViewModel 
{
    [Required]
    [Display(Name = "User Name")]
    public string UserName { get; set; }

    [Required]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [Display(Name = "Remember me?")]
    public bool RememberMe { get; set; }

    /// <summary>
    /// Role
    /// </summary>
    public string Role { get; set; }

}

The error occurs when calling this line in the view:

@Html.TextBoxFor(m => m.UserName)

At this point, Ninject takes over and immediately after returning from the following method in the Ninject.Web.Mvc.Validation.NinjectDataAnnotationsModelValidatorProvider class, the aforementioned unobtrusive validation error occurs. Additionally, I have confirmed that this method has correctly identified the required validations and injected them. The exception is not occurring in this method but afterwards.

protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
    {
        var validators = base.GetValidators(metadata, context, attributes);
        foreach (var modelValidator in validators.OfType<DataAnnotationsModelValidator>())
        {
            var attribute = this.getAttributeMethodInfo.Invoke(modelValidator, new object[0]);
            this.kernel.Inject(attribute);
        }

        return validators;
    }
like image 752
Gustyn Avatar asked Oct 07 '12 15:10

Gustyn


4 Answers

The solution (if Ninject is being used) is to unbind the binding.

kernel.Unbind<ModelValidatorProvider>();

like image 113
stephan.peters Avatar answered Oct 10 '22 06:10

stephan.peters


The error occurs because you are trying to use a mixed validation solution in your project and two providers are trying to add unobtrusive required validation for a field and hence the duplicate issue fires up.

Make sure that you are not using both dataannotation and fluent validation to perform a same validation over a same property (like required in your case).

like image 32
VJAI Avatar answered Oct 10 '22 06:10

VJAI


This is not necessarily a satisfactory answer for everyone on this issue, but I resolved my problem by switching to Unity for my DI. I have determined that, yes, it is because, as Mark said, it is probably due to mixed validation. I am using DataAnnotation in my code; it may be that Ninject is using Fluent Validation internally, but I do not know enough to tell for sure, and don't have the energy to continue on this pursuit since I have found an answer satisfactory to myself.

I like Ninject, but in my case the latest version Unity is actually just as easy to use since all I have to do is add one file (bootstrapper.cs) and call BootStrapper.BuildUnityContainer() from the startup event. So, I will stick with this solution for now.

like image 37
Gustyn Avatar answered Oct 10 '22 06:10

Gustyn


I had the same error in an MVC4 project where I was using fluent validation. My mistake was that I used .NotNull() and .NotEmpty(for the same field):

RuleFor(i => i.SomeValue).NotNull().NotEmpty();

Removing the last .NotEmpty() solved the problem.

like image 44
mightymada Avatar answered Oct 10 '22 06:10

mightymada