I am new to ASP.NET MVC. I am trying to validate some user input. The model behind my view looks like this:
public class ViewModel
{
[Required]
public int? Minimum { get; set; }
[Required]
public int? Maximum { get; set; }
}
My View (.cshtml file) looks like this
@model Website.Models.ViewModel
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
...
<div class="row">
<div class="col-sm-6"><input class="form-control input-sm" id="Minimum" name="Minimum" type="text" /></div>
<div class="col-sm-6"><input class="form-control input-sm" id="Maximum" name="Maximum" type="text" /></div>
</div>
...
<br />
<button type="submit" class="btn btn-primary">Save</button>
}
My controller, looks like this:
public class MyController
{
public ActionResult Edit(int? id)
{
var model = new ViewModel();
return View(model);
}
[HttpPost]
public ActionResult Edit(ViewModel model)
{
if (ModelState.IsValid) {
var result = await model.SaveAsync();
return RedirectToAction("Edit", new { id = result.DemandId, u = "true" });
}
return View(model);
}
}
My code is validating whether the field is provided or not. However, I need to add some business rules. For instance, I need to ensure that Maximum is more than Minimum. If it is not, then I need to give the user an error. I intend to have even more complicated validation scenarios.
My question is, how should I handle these advanced validation scenarios in ASP.NET MVC?
If you are going to make a lot of validation, I can recommend digging into the Fluent Validation library.
Once installed, you'll need to configure the FluentValidationModelValidatorProvider
(which lives in the FluentValidation.Mvc
namespace) during the Application_Start
event of your MVC application.
This enables Fluent Validation to hook into the ModelState
and trigger on ModelState.IsValid
etc.
protected void Application_Start() {
/* Your other initializing code */
FluentValidationModelValidatorProvider.Configure();
}
Then create your validator
public class ViewModelValidator : AbstractValidator<ViewModel> {
public ViewModelValidator() {
RuleFor(x => x.Minimum).NotNull();
RuleFor(x => x.Maximum).NotNull.GreaterThan(x => x.Minimum)
}
}
And hook it onto your ViewModel.
[Validator(typeof(ViewModelValidator))]
public class ViewModel
{
[Required]
public int? Minimum { get; set; }
[Required]
public int? Maximum { get; set; }
}
Here is a list of all inbuilt validation and its easy to create custom, database driving validation as well.
You need to derive your class from IValidatableObject, have a look at this useful article:
http://weblogs.asp.net/scottgu/class-level-model-validation-with-ef-code-first-and-asp-net-mvc-3
One approach is to have a method (either on the controller or a separate validator class which you feed the model to to validate).
This way you can do as much elaborate validation as you like (hitting databases / services / files etc without polluting your POCO View models)
For simplicities sake, lets do it inline to the controller:
[HttpPost]
public ActionResult Edit(ViewModel model)
{
ValidateEditViewModel(model);
if (ModelState.IsValid) {
Inside ValidateEditViewModel:
private void ValidateEditViewModel(ViewModel model){
if(model.. // something is wrong)
{
// this sets ModelState.IsValid = false
ModelState.AddModelError("< PropertyNameThatIsInError >", "The item is removed from your cart");
}
}
Even better is to have a validator class which is injected via DI into the controller and then used throughout (this is more testable and SOLID).
I tend to have a I< ControllerName >ControllerValidator class (so, for the Homecontroller, IHomeControllerValidator), which is implemented by a < Controllername >Validator (HomeValidator) concrete class and injected via unity / dependencyResolver on controller construction.
Works beautifully.
One final extension to this is to have a base controller class of < TValidator > which takes the validator class instance instance and stores it in a consistent place for all controllers that use this base class.
public class BaseController<TValidator> : Controller{
protected TValidator validator;
public BaseController(TValidator validator){
this.validator = validator;
}
}
so HomeController is
public class HomeController : BaseController<IHomeControllerValidator>
{
public HomeController(IHomeControllerValidator validator) : base(validator)
{
}
}
HTH
Use IValidatableObject
interface in your view model.
public class ViewModel : IValidatableObject
{
[Required]
public int? Minimum { get; set; }
[Required]
public int? Maximum { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var results = new List<ValidationResult>();
if (this.Minimum > this.Maximum)
{
results.Add(new ValidationResult("Maximum must be larger than Minimum"));
}
return results;
}
}
This will force ModelState.IsValid
to be false when Minimum > Maximum
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.