Entity Framework post decimal to int field - asp.net-mvc

I am using Entity Framework 6 in an ASP.NET MVC application. I have a field in the model int Time and I post from the client Time = 2.3. The modelState is invalid but without any error. How can I validate this to throw a useful error to the user?

If you are using jquery.validate.js then the form dont even post the info to the post action. This javascript code makes the browser shows a validation error and dont submit the form. However, you can always check the validation yourself if the form submits in the action, like this:
[HttpPost]
public ActionResult Test(YourModelClass vo)
{
if (!ModelState.IsValid)
{
int time;
if (!int.TryParse(Request.Form["Time"].ToString(), out value))
ModelState.AddModelError("Time", "The Test field should be a number");
return View(vo);
}
//do something here with your vo
return View();
}

Related

jquery unobtrusive validation: custom methods do not fire after postback

This is an asp.net framework 4.8 mvc application using jquery unobtrusive validation.
I'm using custom validation methods in the usual fashion.
First, I've added the custom validation attribute in the model:
public class MyValidateAttribute : ValidationAttribute, IClientValidatable
{
private const string errorMessage = "My custom error message.";
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
yield return new ModelClientValidationRule
{
ErrorMessage = errorMessage,
ValidationType = "myvalidateattribute"
};
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
//server-side validation here
}
}
And then applied the validation attribute to a property in the usual fashion:
[MyValidateAttribute]
public bool MyProperty {get;set;}
In javascript I add a matching custom client-side validation method, which is loaded in the $(document).ready() event:
$.validator.addMethod("myvalidateattribute",
function (value, element, param) {
//client side validation here
return false;
}
return true;
});
$.validator.unobtrusive.adapters.addBool("myvalidateattribute");
This works fine. The custom validation fires when I submit the form, which I do like so on a button click:
let $form = $('form');
//clear the validation summary
$form.validate().resetForm();
$form.find("[data-valmsg-summary=true]")
.removeClass("validation-summary-errors")
.addClass("validation-summary-valid")
.find("ul").empty();
//reset unobtrusive field level
$form.find("[data-valmsg-replace]")
.removeClass("field-validation-error")
.addClass("field-validation-valid")
.empty();
if ($form.valid()) {
$form.submit();
}
I've been following this pattern for years and it has worked flawlessly. All of the validation fires client-side, and then fires again server-side. The server-side validation is a failsafe. Any validation problem is caught client-side. Any server-side validation error is assumed to be an attempted hack, and I throw an application exception.
I now have a new requirement where I must do some validation server-side, after the form is posted, and send the form back to the browser in an invalid state if the server-side validation fails. This works, but when I send the model back to the browser none of my custom validation fires.
Here is how the server-side validation looks in the controller method:
public ActionResult MyControllerMethod(MyModel myModel)
{
if (MyServerSideValidationFails(myModel))
{
myModel.MyProperty = false; //this is a validation error
TryValidateModel(myModel);
return View("MyView", myModel);
}
//because of client-side validation any invalid model should be assumed an attempted hack
if (!ModelState.IsValid)
throw new ApplicationException("ModelState should never be invalid.");
//other server-side code here
}
If I now resubmit the form, none of my custom validation fires, and so I get an application exception.
When I step into the $(document).ready event when the model is sent back to the browser, all of my $.validator.addMethod() calls are done successfully. But when I then re-submit, and step into the $form.valid() method in the javascript, I notice that the rules collection for each element does not contain any of my custom validation methods. All of the non-custom validation fires as normal (maxlength, required and etc). Just the custom validation is missed.
It's not just deliberately setting the model invalid on the server that causes the problem. As a workaround, in my controller method, I'm doing a RedirectToAction to the GET method that initially loads the page. Since I don't want the user to lose all of the information in the model, I tried creating a new model, setting all of the properties on that model from the posted model, then storing the new model in TempData. When I'm redirected to the GET action I pulled the model out of TempData and displayed the page using it. I still get the same problem--none of my client-side custom validation fires on re-submission.
It appears that posting the model back, and then loading the page with a model, breaks my client-side custom validation. What am I missing?

Call ASP.NET's input validation after using ValidateInput(false)

When I bash my hands on special characters in the entry fields of my form, when I hit submit, all I get back is a blank page, as ASP.NET detected potentially malicious input and threw an error into my Event Log, all before reaching my MVC controller action.
I would much rather return an error to the user, so they don't just get a blank page. So I want to use ValidateInput(false) and then call the validator from inside my code, so I can send a response. How do I call the validator from an ASP.NET MVC action?
I am little confused with your question .Are you looking for invoking the code which does the model validation ? IF yes you can do that by checking the ModelState.IsValid property. If any of your validation fails, it will return false and in your view you will see the error messages. You can also specify some custom error message from your action method as well if you want to do so.
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
//Model validation is successful. Proceed to other stuff
//If you want to return some custom error message, do like this
ModelState.AddModelError("", "The user name is deactivated");
}
return View(model);
}
Do you want to validate input at server side?
You can use client side validation, you need to add regular expression attribute on your model property and set a nice error message for it. like below
[RegularExpression("your regex", ErrorMessage = #"please check your input .... ")]
public string MyInput { get; set; }

How does the controller receive parameters on HttpPost methods?

Take this snippet out of a controller, for example:
public ActionResult Login()
{
if (User.Identity.IsAuthenticated)
{
return RedirectToAction("Index", "Home");
}
else
{
return View();
}
}
//
// POST: /User/Login
[HttpPost]
public ActionResult Login(LoginModel lm, string returnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(lm.UserName, lm.Password))
{
FormsAuthentication.SetAuthCookie(lm.UserName, lm.RememberMe);
if (Url.IsLocalUrl(returnUrl) &&
returnUrl.Length > 0 &&
returnUrl.StartsWith("/") &&
!returnUrl.StartsWith("//") &&
!returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "Username and Password combination is incorrect");
}
}
return View();
}
My question is, with the overloaded method of Login() (for the HTTP POST), what calls this method with the first parameter as a LoginModel class, and the second parameter as a string? My Login.cshtml view uses a submit button, so I am curious as to how these parameters get passed to the Login() method? What's to stop me from adding a third parameter? And how would that parameter get passed??
I know this is a basic question, I'm just trying to understanding the connecting piece between Views and Controllers.
This process is called Model Binding, lots of resources on it...I would start with How to implement a custom one because from that you will then understand how and why the process works.
http://buildstarted.com/2010/09/12/custom-model-binders-in-mvc-3-with-imodelbinder/
http://bradwilson.typepad.com/blog/2010/10/service-location-pt9-model-binders.html
EDIT:
There is a default model binder which exists which takes items in the post collection like form data and url parameters and tries to match them up with items which you have told the controller to expect. It works something like this...
Request comes in,
MVC decides which controller should get the request
MVC then looks at the HTTP Method, was it a GET or POST?
If it was a post then it looks for the controller action with the HttpPost attribute
MVC then looks at the parameters you have defined...
In your case it says I have a LoginModel and a returnUrl;
MVC now is happy - it knows where things are going so now it looks at what you sent...
It looks at your post data (the form fields and query string parameters)
One by one it looks at their names and then tries to find a match in your controller parameters.
It finds a Username field in the form data, it takes a look at your parameters and asks if there is a Username? No, well maybe Username is a property of LoginModel...it then looks through LoginModel. Aha it says, found one. MVC then creates an instance of LoginModel and sets the Username property to the value you posted.
This process continues for each of the things it finds in your form and query string. There are a bunch of rules it follows but you get the picture - this matching is part of the 'convention over configuration' beauty of MVC.
This whole process above it model binding and since MVC implements this default behavior you do not see it written out in the Global.asax or anything, it is just part of MVC.
Take a look at your LogOn view, this is where the post method gets the returnUrl parameter
Html.BeginForm("LogOn", "Account", new { returnUrl = #Request.QueryString["ReturnUrl"] }

What is ModelState.IsValid valid for in ASP.NET MVC in NerdDinner?

On the NerdDinner example of Professional ASP.NET MVC 1.0 there's a method to create a new dinner as copied bellow (page 89 of the free NerdDinner version).
There it checks ModelState.IsValid for true. It seems to check if the model is valid for the database (that is, it catches data type conversions, like dates with invalid format, but not business rules). Is that true?
When submitting the form, if you have an error in the date, ModelState.IsValid will be false and you'll get back an error, but only for the date because AddRuleViolations was never executed. If you remove the check for ModelState.IsValid completely, then you'll get all the errors (due to the exception), including a marking in the date when it is invalid. Then, why is the check for ModelState.IsValid there at all? Am I missing something?
//
// POST: /Dinners/Create
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Dinner dinner) {
if (ModelState.IsValid) {
try {
dinner.HostedBy = "SomeUser";
dinnerRepository.Add(dinner);
dinnerRepository.Save();
return RedirectToAction("Details", new {id = dinner.DinnerID });
} catch {
ModelState.AddRuleViolations(dinner.GetRuleViolations());
}
}
return View(dinner);
}
ModelState.IsValid tells you if any model errors have been added to ModelState.
The default model binder will add some errors for basic type conversion issues (for example, passing a non-number for something which is an "int"). You can populate ModelState more fully based on whatever validation system you're using.
The sample DataAnnotations model binder will fill model state with validation errors taken from the DataAnnotations attributes on your model.
From the Errata:
ModelState.AddRuleViolations(dinner.GetRuleViolations());
Should be:
ModelState.AddModelErrors(dinner.GetRuleViolations());
Reference: http://www.wrox.com/WileyCDA/WroxTitle/Professional-ASP-NET-MVC-1-0.productCd-0470384611,descCd-ERRATA.html
All the model fields which have definite types, those should be validated when returned to Controller. If any of the model fields are not matching with their defined type, then ModelState.IsValid will return false. Because, These errors will be added in ModelState.
Yes , Jared and Kelly Orr are right.
I use the following code like in edit exception.
foreach (var issue in dinner.GetRuleViolations())
{
ModelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
}
in stead of
ModelState.AddRuleViolations(dinner.GetRuleViolations());

MVC Model Binding

I am using the MVC validation library from link text. I chose this library because I am also using .NetTiers which generates all of the Validation Attributes using MS Enterprise Library Validation Blocks.
It works fine except that that model binding is automatically validating the object and populating the Validation summary. I believe this in normal behavior.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Register([Bind()]NetTiersObject obj)
{
return View();
}
The validation library also has a method that is documented as follows:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Register([Bind()]NetTiersObject obj)
{
try
{
obj.Validate<NetTiersObject>();
}
catch (EntityValidationException ex)
{
ViewData.ModelState.PopulateWithErrors(ex);
}
return View();
}
This also works fine.
My problem is that when using the validation library's method it duplicates the error messages. When just using the model binding the error messages appear strange. The errors have the property name in the message.
So, I think I should either need to format the model binding error messages or disable model binding altogether.
Any recommendation, help?
Thanks.
Have you try:
/*At the Point the ModelState should be Valid(TRUE)
because we still didn't enforce any validations */
var v = ModelState.IsValid;
try
{
obj.Validate<NetTiersObject>();
}
catch (EntityValidationException ex)
{
ViewData.ModelState.PopulateWithErrors(ex);
}
And check if v is True, it should be.
If it is true then obj.Validate<NetTiersObject>(); is doing something wrong because its the only populating the errors duplicated.
My problem is that when using the
validation library's method it
duplicates the error messages. When
just using the model binding the error
messages appear strange. The errors
have the property name in the message.
Its is weird because the modelBinding should not populate Model errors, at least if your are not using a custom Model Binding or trying to save into the DB without validating fields.
I found the answer to why my ModelState was invalid. The form elements do not match up to the model, that is the only way that the ModelState would be invalid immediately.
If I find more specifics I will update this post.

Resources