I'm new at ASP.NET MVC web framework. My database is compound of a single model class("Movie"). I need to validate user's from entering existing data, for instance, a database row could be:
Title - "Indiana Jones and the lost Arc"
Price - $10.00
If another user tries to insert into the database the same data above, provide an error message and prevent from submitting the form collection.
First of all, I think that your question need a "program as answer" but I'll try to suggest you from where to start for working with validation. Suppose you have this model:
class Movie {
public Guid Id { get; set; }
[Required(ErrorMessage="Title is required.")]
[Remote("UniqueTitle", "Validation")]
public String Title { get; set; }
[Required(ErrorMessage="Price is required.")]
public float Price { get; set; }
}
You can decorate it for "simple validation" using Data Annotation. I've used a specific attribute, called Remote.
This attribute allow you to define a custom, server-side, logic to validate the model.
Now, you can create a validation controller where check that provided value is not already in use:
class ValidationController : Controller {
private IDbContext db = ...;
public ActionResult UniqueTitle(String title) {
var item = db.Movies.FirstOrDefault(m => m.Title.Equals(title));
return Json(item == null, JsonRequestBehavior.AllowGet);
}
}
Now you are ready to validate your model.
I hope this can help.
Related
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 !
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.
I've been googling like crazy without result, maybe I'm just missing the correct keywords.
I have a class with a custom validation attribute on a property. I want to "clean" the value before validation, removing the white-space and special characters that we accept but that we don't want to save to the database.
public class PersonViewModel
{
[SocialSecurityNumberLuhn(ErrorMessage = "Incorrect social security number")]
public string SocialSecurityNumber { get; set; }
}
I would want to do something like this:
public class PersonViewModel
{
[CleanWhiteSpace]
[SocialSecurityNumberLuhn(ErrorMessage = "Incorrect social security number")]
public string SocialSecurityNumber { get; set; }
}
For example 1985-03-15-1234 should be saved and validated as 19850315-1234.
Any suggestions? What's the neatest approach?
If you change the auto-implemented property into a manual-implemented property then you can perform the "cleaning" step when the value is set, so it can only be stored in the model in a "clean" state. Something like this:
public class PersonViewModel
{
private string _socialSecurityNumber;
[SocialSecurityNumberLuhn(ErrorMessage = "Incorrect social security number")]
public string SocialSecurityNumber
{
get { return _socialSecurityNumber; }
set
{
_socialSecurityNumber = CleanSocialSecurityNumber(value);
}
}
}
The recommended approach here is to use a service layer. View models should not include any logic. With a service layer Your controller would call a method on its associated service and this method would return your view model with the clean SSN.
In this tutorial you will see how the service layer can be structured and you could adapt the pattern to clean your data before validation.
http://www.asp.net/mvc/tutorials/older-versions/models-(data)/validating-with-a-service-layer-cs
The use of a ValidationAttribute in your example would be an incorrect usage also.
Controller where you would inject / instantiate the service class
public ActionResult GetPerson(int PersonId){
return _personService.GetPerson(personId);
}
The service method
public PersonViewModel GetPerson(int Id){
// get the data (maybe from DAL) and clean returning view model
return new PersonViewModel(){SocialSecurityNumber = Clean(...)};
}
Hope this gives you some direction.
How can we validate data based on action being taken over particular entity? What other more advanced alternatives are there to data annotations model validation? Possibly pluggable into Asp.net MVC and WebAPI, so validation is still being done automatically.
Example
Suppose a user join form of a web application.
public class User
{
// required when providing user as input
// not provided when creating new instance
public int Id { get; set; }
// required when user joins and of specific format AND IS UNIQUE based on data store users
// optional when providing user as input
public string Email { get; set; }
...
}
Maybe object inheritance could help but as much as I think of it, inheritance would only be as a hack. Base class would hardly have any properties and we could end up with several extremely similar (properties) classes but with different annotations just to use data annotations. And that's not good.
Desired implementation
I was thinking of validation based on action being taken over particular entity. So we'd be able to define something like:
public class User
{
[Required(Action = ValidationAction.Provide)] // or whatever action we'd define
public int Id { get; set; }
[Required(Action = ValidationAction.Create)]
[IsUnique(Action = ValidationAction.Create)] // custom DataAnnotations validator
[EmailAddress]
public string Email { get; set; }
...
}
Asp.net MVC and WebAPI controller actions would require some sort of attribute to provide information what's being done with particular entities a parameters
[HttpPost]
[ValidateForAction("user", ValidationAction.Create)]
[ValidateForAction("user.InvitedBy", ValidationAction.Provide)]
public ActionResult Join(User user)
{
...
}
or set it uniformly for all parameters (and their object entities in subtrees)
[HttpPost]
[ValidateForAction(ValidationAction.Create)]
public ActionResult Join(User user)
{
...
}
When ValidateForActionAttribute isn't present on controller action validation should only check validation action independent annotations (like the EmailAddressAttribute set above on my entity example).
A similar example could be Stackoverflow scenario of adding an answer where posted answer details would be validated by create action, and related question entity (a property inside an answer) would be validated per provide action because we'd mainly just need its Id.
Is there any such validation library? Anybody done something similar?
How would you go about doing such validation?
This sounds like its similar to a requiredif validator where the validation is dependent upon another property. However, model validation will not work here since the model is "supposed" to be independent of views or controllers.
Assume though that you have a view model associated with individual actions on a controller, then the view model could use data annotations consistent with the requirements of the view. See ASP.Net MVC and MVVM for more detail on the MVVM pattern.
One last comment with regard to the Id. Not sure a Required attribute will work since the default for an int is a valid value. Perhaps a regex? ([1-9]|[0-9]{2,10})
public class RegistrationController
[HttpPost]
public ActionResult Provide(UserProvideViewModel user)
{
...
}
[HttpPost]
public ActionResult Join(UserJoinViewModel user)
{
...
}
}
[MetadataType(typeof(UserProvideViewModel_Validation))]
public partial class UserProvideViewModel : User
{
// properties unique to the view model
}
public class UserProvideViewModel_Validation
{
[RegularExpression(#"^([1-9]|\d{2,10})$")]
public Id { get; set; }
}
[MetadataType(typeof(UserJoinViewModel_Validation))]
public partial class UserJoinViewModel : User
{
// properties unique to the view model
}
public class UserJoinViewModel_Validation
{
[Required]
[EmailAddress]
public Email { get; set; }
}
I'm wanting to check if I can send a message from a Model to a Controller, I'll explain.
So I have a Model
public class Car()
{
public int Id { get; set; }
public string Make { get; set; }
}
So when a user adds a new Car, I could make it required by using Fluent API or the [Required] annotation.
But what if I wanted to make sure I had only certain characters in there, so I wouldn't want the percentage symbol in there (unless there are any cars out there?!).
So I thought I'll use a constructor:
public class Car()
{
public Car(string _name)
{
if(this.Make.Contains("%"))
{
//Let the user know this isn't valid there is an error
}
}
public int Id { get; set; }
public string Make { get; set; }
}
I usually place the error logic in the Controller. So I would have
public ActionResult AddCar(Car car)
{
if(car.Make.Contains("%"))
{
//let user know this is not valid
}
if(ModelState.IsValid)
{
}
///
}
But then I thought, I'm never going to want to have a car Make with a % sign (I've picked on % sign, but actually there is a host of validation I would use, such as a list containing invalid characters), and every place in which I allowed for a user to add a car, I would duplicate the validation code, which just felt inefficient.
Maybe producing a the error checking in the controller is the correct way?
Again for clarity. The question, is there a way to pass a message from a Model to a Controller, which I can then pass to the User's view?
Kind regards
You should not use validation logic in your controller, we have DataAnnotations which allows us to validate model's properties value.
for your purpose you can use RegularExpression validator for this.
Refer to this Link for more details
I am still just a couple days into ASP.NET and WebAPI frameworks so I must be missing out something really simple.
I have a model that has a couple properties and ID (as a property, which has a private setter but that didn't help).
public long ID { get; private set; }
[Required(ErrorMessage = "Location coordinate X is required.")]
public double X { get; set; }
[Required(ErrorMessage = "Location coordinate Y is required.")]
public double Y { get; set; }
And then I have a controller method post:
public HttpResponseMessage Post(MyModel model)
When I start the project and go to auto-generated API documentation, I can see that samples include ID as an input field. I want API to ignore ID input field. I could just ignore it myself but I don't like such must-remember-not-to-use things in my code.
One option would be to create a separate model just for the input but it would mean I have to maintain two classes instead of one.
Is there any data annotation to ignore this property entirely?
Try with:
[ScaffoldColumn(false)]
The ID property will no longer be seen by the html helpers. However, the model binder might still try to move a value into the ID property if it sees a matching value in the request.
So you decorate it with Exclude to avoid property to be binded:
[Exclude]
public long ID { get; set; }
You can also , (inside your Post function) remove the property from state:
ModelState.Remove("Id"); // Key removal
if (ModelState.IsValid)
{
}
}