1

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?

2
  • 2
    Why are Minimum and Maximum nullable if they're required? Commented Feb 20, 2015 at 14:00
  • You can also use foolproof validation attributes such as [GreaterThan("Minimum")] to give you client and server side validation (but you need to generate the controls correctly using @Html.TextBoxFor() and @Html.ValidationMessageFor() Commented Feb 20, 2015 at 22:45

4 Answers 4

3

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.

Sign up to request clarification or add additional context in comments.

Comments

2

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

6 Comments

While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes.
Referencing the Gu was all I needed to see
@Verdolino, have you read the Url of the link, what did you think he was likely to change the linked page too?
@justinharvey It is better to include the essential parts of the answer here and provide the link for reference.
@Verdolino, you have just said what you said last time, except now without any justifaction.
|
1

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 Viewmodels)

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

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.