MVC 3, NHIbernate Validators & Message Interpolator - validation

I have followed this article and have a passing test showing custom validation error messages being returned from a resource file when a call to Validator.IsValid(someEntity) fails.
I am trying to translate this to the new unobtrusive client-side validation in MVC3 describe by this article. This also more or less works - well the client-side validation does so I can assume my wiring of NHValidators is good, as you can see the following is output:
<input data-val="true" data-val-required="{NotNullNotEmpty}" id="Username" name="Username" type="text" value="" />
<span class="field-validation-valid" data-valmsg-for="Username" data-valmsg-replace="true">
My problem is that this time the CustomMessageInterpolator has not fired - the resource string has not been translated for this property (it's still in curly braces): {NotNullNotEmpty}.
Both my test and the web are usign the same NHValidator config:
var cfg = new FluentConfiguration();
cfg
.SetMessageInterpolator<CustomMessageInterpolator>()
.SetCustomResourceManager("MyProject.Core.Resources.ValidationMessages", Assembly.Load("MyProject.Core"))
.SetDefaultValidatorMode(ValidatorMode.UseAttribute)
.Register(Assembly.Load("MyProject.Core").ValidationDefinitions())
Just for good measure here's the model snippet:
public class LoginModel
{
[NotNullNotEmpty(Message = "{NotNullNotEmpty}")]
public string Username { get; set; }
Long shot I know but any ideas would be appreciated!

I had no luck with this having posted it around a few forums.
In the end I've resorted to using DataAnnotations instead in my View Models for client-side validation.
Of course this is really hacky and a horrible "solution" as I've now two types of validation attributes in my code. (if wondering, yes I'd rather keep my NH Validation attributes 1. as I'm still generating my schema from them and 2. I like the way NH validates before committing to the db i.e. server-side).
If interested, here's how to use resource files to show the correct labels for your controls.
This code snippet shows how to then also rig up custom error messages:
[DisplayResource(typeof(LabelResources))]
public class NewChildTagViewModel : ModuleViewModel
{
public int ParentId { get; set; }
[Required]
public string Title { get; set; }
[Range(1, 1000, ErrorMessageResourceType = typeof(ValidationMessages), ErrorMessageResourceName = "Display_Order")]
[Required]
public int? DisplayOrder { get; set; }
}

Can you show your code? I presume you used some sort of custom ModelValidatorProvider?
I've got something working like what you described. It required writing a custom AssociatedValidatorProvider and ModelValidator, along the lines described here
http://weblogs.asp.net/srkirkland/archive/2010/07/20/nhibernate-client-validator-asp-net-mvc-2-model-validation.aspx
but changing the MessageOrDefault method in the article above to use the NHibernate Validator DefaultMessageInterpolator to translate the messages.
It sounds like you got most of the way towards getting something working, and you just needed to use the DefaultMessageInterpolator to translate the messages.

Related

I have a complex View Model that has built complex named html elements. How do I build a matching post model?

I have a lot of data that needs to be passed from a controller to a view and I am trying to use strongly typed View Models where possible.
Take an example where you have a database of loads of people - We want to edit a person whilst also presenting a list of everyone with the same surname.
public class person
{
public string ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class testviewmodel
{
public List<person> people { get; set; }
public person newperson { get; set; }
}
I can't use testviewmodel as the model for the post because there is a lot more going on in the form/data. I have managed to build a model that contains nearly all the form data, other than the ones from the View Model.
I generate some items in the form via:
<input asp-for="newperson.Firstname" class="form-control"/>
This in return generates:
<input class="form-control" disabled type="text" id="newperson_Firstname" name="newperson_Firstname" value="xxxx" />
However, I have tried adding newperson_Firstnameto my model alongside quite a few other combinations, and, I am just not able to see the data.
Can anyone please assist and let me know what I am doing wrong - or, should I just be adjusting the view model to be more fit for purpose?
...Lastly, is there any equivalent of var_dump($_REQUEST);? At the moment, I'm adding breakpoints and trying to open up different items within Locals, but, it's trial and error and taking ages... I'm just trying to find where the form is!
You shouldn't need to dig around in the Request object. If you pass an instance of your ViewModel to your post action, model binding will take care of populating the Person property automatically:
[HttpPost]
public IActionResult Edit(TestviewModel model)
{
var person = model.Person; // add a breakpoint here, should represent the posted values
}

Server validation does not trigger when submitting with Ajax Asp Mvc3 with kendo + knockout

I have Asp Mvc3 app. In my view I am using kendoui + knockoutjs. I am handling the client side validation with kendo validator. I am very new to asp mvc3 and I cannot make my server side validation work.
This is my business object:
[Validator(typeof(FranchiseInfoValidator))]
public class FranchiseInfo
{
public string FullName { get; set; }
public string ShortName { get; set; }
}
}
I am using FluentValidation. This is the implementation of my validation rules:
public class FranchiseInfoValidator : AbstractValidator<FranchiseInfo>
{
public FranchiseInfoValidator()
{
RuleFor(franchiseInfo => franchiseInfo.FullName).NotEmpty();
RuleFor(franchiseInfo => franchiseInfo.ShortName).NotEmpty();
}
}
This is my view model:
public class FranchiseInfoViewModel
{
public string FullName { get; set; }
public string ShortName { get; set; }
}
This is my view strongly typed to FranchiseInfoViewModel:
#model MvcApplication2.Models.FranchiseInfoViewModel
<script src="../../Scripts/Details.js" type="text/javascript"></script>
<form id="franchiseForm" action="" style="font-family: Trebuchet MS, Verdana, Helvetica, Sans-Serif;">
<table>
<tr>
<td><label for="fullName">FullName:</label></td>
<td><input id="fullName" data-bind= "value: FullName" /></td>
</tr>
<tr>
<td><label for="shortName">ShortName:</label></td>
<td><input id="shortName" data-bind= "value: shortName" /></td>
</tr>
</table>
<button id="submit" class="k-button" data-bind="click: save" form="franchiseForm">Save Franchise</button>
</form>
On submit the form I am calling javascript function save:
$(function () {
save = function () {
// some logic
$.ajax({
url: "/franchise/SaveFranchise",
type: "POST",
data: { franchiseInfoViewModel: jsonData },
dataType: 'json',
success: function (data, textStatus, xhr) {
window.location.href = data.redirectToUrl;
}
});
}
});
On save I am submitting the data in json format and sending the data to the SaveFranchise Controller:
public ActionResult SaveFranchise(string franchiseInfoViewModel)
{
var franchiseInfoVM = JsonConvert.DeserializeObject<FranchiseInfoViewModel>(franchiseInfoViewModel);
if (!ModelState.IsValid)
{
// do some action
}
return View();
}
What I want to accomplish is on (!ModelState.IsValid) to return back to the view and show fluent validation error messages. For some reason, in my case ModelState.IsValid is always true.
As mentioned, I am very new to Asp Mvc 3. From the articles I have read, the examples are submitting the form to the server (without javascript) where there is binding and the server validation messages are returned to the view. But there the view is implemented with Razor and client side validation is done via jquery.
In my view I am using javascript view model with databindings ( kendoui + knockout). What should I do to do the server side validation in my case. Please help me. Thank You for your time and effort!
Short answer:
You should make use of model bindings in the controller action - doing so enables you to make use of ModelState.IsValid.
So your controller action:
public ActionResult SaveFranchise(string franchiseInfoViewModel)
.. should be changed into something like:
public ActionResult Create(FranchiseInfo franchiseInfo)
Be sure to post your form in a format that enables the model binder to instantiate an instance of the FranchiseInfo model. You can use JSON to do so, but I think it would be better (and simpler) if you just post the form using the standard action attribute on a form.
Elaborated answer:
One of the first things I would recommend, is that you use the model validation provided by the ASP.NET MVC framework including model bindings, model state, and data annotations for server side validation, as well as unobtrusive javascript for client side validation. Doing so would give you a way more DRY implementation with clear Separation of Concerns (SoC).
To get there - I suggest you first start taking a look at model bindings in ASP.NET MVC.
As stated in "The Features and Foibles of ASP.NET MVC Model Binding":
With model binding, controller actions can be focused on providing business value and avoid wasting time with mundane request mapping and parsing.
To see this, this MSDN article have a good definition of a model binder:
A model binder in MVC provides a simple way to map posted form values to a .NET Framework type and pass the type to an action method as a parameter. (...) Model binders are like type converters, because they can convert HTTP requests into objects that are passed to an action method.
With that abstraction in hand, you will quickly see that the signature of:
public ActionResult SaveFranchise(string franchiseInfoViewModel)
.. could be changed into something like:
public ActionResult Create(FranchiseInfo franchiseInfo)
... and at this point, things are already starting to look more clean because code like your custom data mapping:
var franchiseInfoVM = JsonConvert.DeserializeObject<FranchiseInfoViewModel>(franchiseInfoViewModel);
... can be removed.
In general, you should not need to serialize the form into JSON and post that - instead you should take advantage of the model binding in MVC and submit the form data the standard way ( by using the action attribute on the form element - well, the model binder is able to bind objects based on JSON, but I think you get my point.. ). Actually, ASP.NET MVC makes it really simple to generate a form for a model using Html.BeginForm - an example use of this is shown here.
So, now when you have refactored the view to make use of a form that posts its data without serializing the form data into JSON, you should take a look at the data annotations in MVC3.
As mentioned in this example, the System.ComponentModel.DataAnnotations namespace of .NET...
provides a built-in set of validation attributes that you can apply declaratively to any class or property. (...) The validation attributes specify behavior that you want to enforce on the model properties they are applied to.
One of the available annotations is the Required attribute - it defines that a particular model property must have a value. There are several other attributes like Range, MaxLength, RegularExpression, etc. An example use of some of the attributes could look like this:
public class Movie
{
public int ID { get; set; }
[Required(ErrorMessage = "Title is required")]
public string Title { get; set; }
[Required(ErrorMessage = "Date is required")]
public DateTime ReleaseDate { get; set; }
[Required(ErrorMessage = "Genre must be specified")]
public string Genre { get; set; }
[Required(ErrorMessage = "Price Required")]
[Range(1, 100, ErrorMessage = "Price must be between $1 and $100")]
public decimal Price { get; set; }
[StringLength(5)]
public string Rating { get; set; }
}
( The example is borrowed from: http://www.asp.net/mvc/tutorials/getting-started-with-aspnet-mvc3/cs/adding-validation-to-the-model )
Populating your models with data annotations makes it very easy for you to check if the model is valid or not, at the point when a given form has been submitted, and your are about the check the validity of the provided model in a given action - it is here ModelState.IsValid proves to be useful.
As mentioned in this post:
(...) The second Create method calls ModelState.IsValid to check whether the movie has any validation errors. Calling this method evaluates any validation attributes that have been applied to the object.
So at this point, you should be able to see that using data annotations to declare constraints/required behavior on your model will allow you to have a simple implementation where the logic is defined in the model and can easily be checked using ModelState.IsValid.
To expand a bit on this I can tell you a bit of my experience with model validation at server and client side in ASP.NET MVC3.
As you might already have guessed, my best experience with ASP.NET MVC3 when it comes to model validation is using data annotations and the built-in support for server-side validation through ModelState.IsValid and client-side validation through unobtrusive JavaScript.
For data annotations I use a combination of the built-in annotations, and the extensions provided by the data annotation extension project.
There are a couple of good things about using ASP.NET MVC3's support for unobtrusive client validation.
First of all, SoC is really easy to achieve, as the model validation logic is only defined one place - and that is in the model where it belongs.
Secondly you can get a more DRY implementation in your view ( avoid duplicated logic and get code that is easier to maintain ) and let the framework do the heavy lifting for you instead.
An example of how to use unobtrusive client side validation in ASP.NET MVC3 can be found here.
However, there are times when using the annotations might not seem that straigt forward - for instance when you want to validate properties such as credit cards and file extensions. In these cases where the need for logic calls for alternatives other than the basic annotations, I tend to use data annotation extensions ( unless I can target my application for .NET 4.5 which, for instance, has added a series of more attributes, like e.g. the FileExtensionAttribute ) as they provide a series of great annotation extensions that just works right out of the box ( there exist a data annotation extensions nuget package for MVC3 - so it is really simple to set up and start using ).
There are also special cases when you might have a property that depends on the state of your databse - e.g. if you want to check if a username already exists when a user is filling out a user registration form. In this scenario, the ASP.NET MVC3 remote validation annotation is your friend. As this MSDN article states:
ASP.NET MVC 3 provides a mechanism that can make a remote server call in order to validate a form field without posting the entire form to the server. This is useful when you have a field that cannot be validated on the client and is therefore likely to fail validation when the form is submitted.
And the nice thing about remote validation in ASP.NET MVC3 is, that it also is expressed using a data annotation ( as illustrated in this blogpost and in this MSDN article ).
So to sum up - using these framework features (imo) really gives you a serious range of tools to cover more or less any kind of model validation "the right way" in ASP.NET MVC3.

validation message is not showing in client side in mvc razor

I am working on MVC Razor and I want to validate my model as per condition.
codtion is if IsDefaultMailingAddress is true then only DeliveryLine and Zip will be Required otherwise page is submitted.
I have searched so many artical and got below metion blog
http://blogs.msdn.com/b/simonince/archive/2011/02/04/conditional-validation-in-asp-net-mvc-3.aspx
and I have implemented Reqiuedif in my model which is mentioned below
my model:
RequiredIf("IsDefaultMailingAddress",true, ErrorMessage = "Must add DeliveryLine ")]
public string DeliveryLine { get; set; }
RequiredIf("IsDefaultMailingAddress",true, ErrorMessage = "Must add Zip")]
public string Zip { get; set; }
public bool IsDefaultMailingAddress { get; set; }
Everything is working fine but the Problem is when i click submit buttion it is going to server side and there model state isvalid
showing false.why before going to server it is not showing all error message
"Must add DeliveryLine and Must add Zip"
please let me know what what should be implement this client side validation.
You should have to enable ClinetValidation to get work around this. In the view just add the below html helper.
#Html.EnableClientValidation()

Validate DateTime with FluentValidator

This is my ViewModel class:
public class CreatePersonModel
{
public string Name { get; set; }
public DateTime DateBirth { get; set; }
public string Email { get; set; }
}
CreatePerson.cshtml
#model ViewModels.CreatePersonModel
#{
ViewBag.Title = "Create Person";
}
<h2>#ViewBag.Title</h2>
#using (Html.BeginForm())
{
<fieldset>
<legend>RegisterModel</legend>
#Html.EditorForModel()
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
CreatePersonValidator.cs
public class CreatePersonValidator : AbstractValidator<CreatePersonModel>
{
public CreatePersonValidator()
{
RuleFor(p => p.Name)
.NotEmpty().WithMessage("campo obrigatório")
.Length(5, 30).WithMessage("mínimo de {0} e máximo de {1} caractéres", 5, 30)
.Must((p, n) => n.Any(c => c == ' ')).WithMessage("deve conter nome e sobrenome");
RuleFor(p => p.DateBirth)
.NotEmpty().WithMessage("campo obrigatório")
.LessThan(p => DateTime.Now).WithMessage("a data deve estar no passado");
RuleFor(p => p.Email)
.NotEmpty().WithMessage("campo obrigatório")
.EmailAddress().WithMessage("email inválido")
.OnAnyFailure(p => p.Email = "");
}
}
When trying to create a person with an invalid date format:
Observations
As in my CreatePersonModel class the DateBirth property is a DateTime type, the asp.net MVC validation has done for me.
But I want to customize the error message using the FluentValidation.
I do not want to change the type of property for various reasons such as:
In a CreatePersonValidator.cs class, validation is to check if the date is in the past:
.LessThan (p => DateTime.Now)
Question
How to customize the error message without using DataAnnotations (using FluentValidator).
public CreatePersonValidator()
{
RuleFor(courseOffering => courseOffering.StartDate)
.Must(BeAValidDate).WithMessage("Start date is required");
//....
}
private bool BeAValidDate(DateTime date)
{
return !date.Equals(default(DateTime));
}
Have a look at the Fluent Validation documentation on GitHub:
https://github.com/JeremySkinner/FluentValidation/wiki
Try adding a RegEx Validator to ensure that the user's input (a string) can be parsed as a date correctly, prior to applying the Less Than Validator.
EDIT
Having run few test cases and looked at the source code for Fluent Validator I concede that the above approach won't work.
The standard error you get is added during the Model Binding phase, which happens before the fluent validation framework can access and check the model.
I assumed that the framework's authors had been clever and were injecting their validation code into the model binding phase. Looks like they aren't.
So the short answer is what you want to do does not appear to be possible.
Try this one
RuleFor(f =>
f.StartDate).Cascade(CascadeMode.StopOnFirstFailure).NotEmpty()
.Must(date => date != default(DateTime))
.WithMessage("Start date is required");
As Stewart mentioned, it's not possible to use FluentValidation alone to get in front of the model binding in this way. I'd offer up two ideas/suggestions though:
If you really can't change the ViewModel type from DateTime to string, you could always clear the model state yourself after model binding and then run the validator manually (I'm assuming you've wired FluentValidation to execute automatically after model binding).
In scenarios like this, I would change the property to a string, but then use AutoMapper to map that into a DateTime for whatever business object / domain model / service contract request I need it to ultimately become. That way, you get the most flexibility with parsing and conversion on both sides of the model binding.
I got this to work with DateTime? using really simple code. If you use the built-in validator NotNull(), then you get client side validation, which has 2 benefits.
You don't have to worry about all the model binding stuff people are talking about in other answers. It's client side! ;)
The date the user entered does not get "wiped out". An invalid date will get set by to null by the Post, Model binding to null, Validation error, responding with the view now with a null value in the date. This happens fast, so the user does not see what is wrong with the date.
This is the code I used:
RuleFor(x => x.CompleteDate).NotNull().WithMessage("Complete Date is not a valid date.");
I tested it with a date of 11/31/2021 (There is no day 31 in November) and it worked great with client-side validation.
Win!

Validating parameters passed through the URL

I am working on an ASP.Net MVC3 application and I'm having trouble understanding the "right way" to do the validation I'm looking for.
For example, consider a model that looks like this:
[Required]
[StringLength(10, MinimumLength = 10)]
[RegularExpression("[0-9]{10}")]
public string Id { get; set; }
[Required]
public string Value { get; set; }
If I have an Id of "2342" and try to POST back, the model mapping kicks in and registers an error because of the length validation. However, if perform a GET against /controller/2342, then MVC seems to happily create a model with this invalid state (ModelState.Valid will be true). I could create some validations in the controller to catch this, but it seems redundant.
What is the best way to do this?
Thanks!
Jacob
When you perform a GET, you are simply retrieving a model with a given ID. So there is no validation performed. If you really want to make sure that requested model IDs should be 10 numbers in length, you should define constraint in Global.asax:
routes.MapRoute(
"Product",
"Product/{productId}",
new {controller="Product", action="Details"},
new {productId = #"[0-9]{10}" }
);
There is nothing in the framework that by default validates a model on a GET request as validation isn't generally required at that time. If you do want to force a validation here, this was answered in this prior question
See:
Validate model on initial request

Resources