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; }
Related
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?
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();
}
After reading about XSS attacks I have applied the AntiForgeryToken to my website using the ValidateAntiForgeryTokenWrapperAttribute described in this article:
http://weblogs.asp.net/dixin/archive/2010/05/22/anti-forgery-request-recipes-for-asp-net-mvc-and-ajax.aspx
It seems to work well however I've come across a problem when using Remote Validation in MVC3. I have a ValidationController which contains all of the common validation within my site and if I apply the ValidateAntiForgeryTokenWrapperAttribute to it then the remote validation no longer works and I get an 'A required anti-forgery token was not supplied or was invalid.' exception logged in Elmah. I've tried debugging this and it doesn't even hit the controller action before throwing the exception. I assume this happens because the remote validation doesn't know to pass the AntiForgeryToken to the controller - has anyone else had this problem or knows whether the two are not meant to be used together?
It also made me question whether I should be using the ValidateAntiForgeryTokenWrapperAttribute on every controller or not, any thoughts?
In the remote attribute do as below:
[Remote("MyValidationMethod","MyController", HttpMethod = "POST", AdditionalFields = "__RequestVerificationToken")]
public object MyField { get; set; }
the AdditionalFields property can accept comma separated fields names in the form; the __RequestVerificationToken is the name of the hidden field which contains the AntiForgeryToken.
I haven't used Remote Validation. However I had similar experience with AntiForgeryToken. When I had it applied for all the actions in my controller. Later, I removed it from all the actions and applied to only those actions which were sending data back to database (insert/update/delete).
As it seems you have applied AntiForgeryToken validation attribute to entire controller, it will always create a new token value every time an action is executed and so when response goes back to client for remote validation action the value of token is different than what is on the form which gets submitted later for other actions.
You can remove AntiForgeryToken attribute from the controller and use it with other action apart from remote validation action or wherever you really need it.
//Instead of this
[ValidateAntiForgeryToken]
public class mycontroller
{
//...
}
//Do something like this
public class mycontroller
{
public ActionResult myotheraction ()
{ }
[ValidateAntiForgeryToken]
public ActionResult valdaitionaction ()
{ }
}
I am using Entity Framework + SQL Server DB and am using partial classes with DataAnnotations to validate data. For things like Required and Range, this works fine, but I am unable to get the DataType validators to work.
Here is an example of the (custom) annotation:
[DataTypeWholeNumberAttribute(ErrorMessage = "Zip must be a whole number")]
public object Zip{ get; set; }
...and the Controller Code...
[HttpPost]
public ActionResult Edit(NamedInsuredViewModel viewModel)
{
try
{ //breakpoint here (opening squiggly bracket) shows .Zip is already null
if (ModelState.IsValid)
...save, etc...
}
}
And I know what's happening: The DataType of Zip in the database is int, so the default validation is catching that and applying the generic error message "the value [x] is not valid for [FieldName]" before my validator can get to it (to prove this, I also added the same validator to a string field, and it works just fine). What I don't know is, how can I get around that (and no, I can't change the DB to use strings for everything)?
Some suggestions have been offered in this post (http://forums.asp.net/p/1608322/4162819.aspx#4162819), but so far nothing has helped.
Thanks in advance.
PS - is there really no way to validate a primitive DataType without creating a custom Attribute?
I think the error is to pass something called "viewModel" to a Edit Action.
ViewModel is intended for pass data to a view to render it.
When you submit a form the data have to be mapped to a entity not to a viewModel.
[HttpPost]
public ActionResult Edit(YourEntity entity)
{
try
{ //breakpoint here (opening squiggly bracket) shows .Zip is already null
if (ModelState.IsValid)
...save, etc...
}
}
Apply your custom validator to the class. Then pass in your class instance as the parameter for your validator instead of as a string. Then you can perform the validation on the appropriate property regardless of type.
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.