0

I have a model described as below:

    public class Projet
    {
    public int ProjetId { get; set; }

    public int SeqNumber{ get; set; }
    public string Code{ get; set; }
    public string Description { get; set; }
    public bool Std{ get; set; }
    public bool Archive { get; set; }
    }

I have a create view to let a user create a new project, and I must let the SeqNumber field free so the user can input whatever number he wants. However, I must return an error if the SeqNumber choosen is already taken.

I'm not sure how to implement this. Should I do some validation in my ProjetsController/Create action ? From what I can find, validating stuff in the controller is a bad practise, but I can't think of where to implement validation when it depends on other members of the same class. Would coding a custom validator for MVC considered a good practise?

Thanks !

JonD
  • 5
  • 2
  • I guess you are look for *Remote Validation* a good place to start: https://msdn.microsoft.com/en-us/library/gg508808(vs.98).aspx – Daniel Dec 23 '16 at 15:05
  • There is nothing wrong with validating the value in the Create action. In fact, depending on the semantics of the field, this could be a business rule in which case it SHOULD be validated in the backend. That being said, you can always code your own validation scheme with some JS and fire a method on the backend (like a web service or something) to see if the value exists. I would still recommend doing it at the backend though. – JuanR Dec 23 '16 at 15:15

1 Answers1

0

You can use this in your http post action method which handles the form submit

[HttpPost]
public ActionResult Create(Projet model)
{
   var exist = db.Projects.Any(s=>s.SeqNumber===model.SeqNumber 
                                && s.ProjectId!=model.ProjectId);
   if(exist)
   {
     ModelState.AddModelError(string.empty,"Sequence number is already in use");
    return View(model);
   }
   // to do : Continue with your save
}

Now when user submits the form, if the sequence number is being used for any other project, it will throw a validation message. Make sure you are using the Validation summary helper in your view to render the validation error message.

@model Project
@Html.ValidationSummary(false)
@using(Html.BeginForm())
{
   <!-- your existing code goes here-->
} 

Now to give a nice user experience, you may take advantage of the Remote validation feature. What it does is, when user takes the focus out from the input, it makes an ajax call to server to check whether your SequenceNumber exist in db. Based on the result, the validation messages will be shown to the user.

To do this, decorate your property with the Remote attribute.

 [Required]
 [System.Web.Mvc.Remote("CheckSeqNumber", "Project", 
                                             ErrorMessage = "SeqNumber is already used!")]
 public int SeqNumber { get; set; }

Now make sure you have an action method called CheckSeqNumber which returns either true or false as a json response.

public ActionResult CheckTagName(int SeqNumber)
{
  var exist= !db.Projects.Any(g => g.SeqNumber == SeqNumber);
  return Json(exist,JsonRequestBehavior.AllowGet);
}

Also make sure you have the relevant javascript files loaded to do this unobtrusive validation.

<script src="~/Scripts/jquery.validate.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.js"></script>

Another option is to write a custom validation attribute which does this check for you (if you do not like that check in the action method). Here is an SO post explaining how to do it.

Community
  • 1
  • 1
Shyju
  • 214,206
  • 104
  • 411
  • 497