Validating single Property in model which is binded customly - c#

I want to simply validate a single property of that model
public ActionResult Rate([Bind(Exclude="Score")]RatingModel model)
{
if(ModelState.IsValid)
{
//here model is validated without check Score property validations
model.Score = ParseScore( Request.Form("score"));
// Now i have updated Score property manualy and now i want to validate Score property
}
}
after assign Score manually, Mvc framework does not check validation on model. Now i want to validate Score property with all validation attributes which currently exist on model.
// How to do that easily ? Mvc Framework support this scenario ?
Here is my model
public class RatingModel
{
[Range(0,5),Required]
public int Score { get; set; }
}

I have found right solution. I simply call TryValidateModel and it validate properties include Score property.
public ActionResult Rate([Bind(Exclude="Score")]RatingModel model)
{
model.Score = ParseScore( Request.Form("score"));
if(TryValidateModel(model))
{
///validated with all validations
}
}

You're using MVC3. Any particular reason why you aren't setting some of the most basic validation rules in the Model?
You can set some validation rules directly in the model. For example, if you want to validate an email field, you can set the rules and even the error messages in the model itself.
[Required(ErrorMessage = "You must type in something in the field.")]
[RegularExpression(".+\\#.+\\..+", ErrorMessage = "You must type in a valid email address.")]
[Display(Name = "Email:")]
public string Email { get; set; }
Read more here:
http://www.asp.net/mvc/tutorials/validation-with-the-data-annotation-validators-cs

You need to check if the ModelState is valid in the Controller Action:
public ActionResult Action(RatingModel viewModel)
{
if (ModelState.IsValid)
{
//Model is validated
}
else
{
return View(viewModel);
}
}

Related

ModelState Contains String Required Properties Twice

I'm developing an Asp.Net Core 2.1 App using Razor Pages.I've come down with an odd behavior.The problem is when I submit a form,the client side validation passes with all required properties filled out,but then the validation fails with the ModelState.IsValid check,and the reason is that the ModelState contains the required string properties twice,one with the value entered and one with null value,So the validation fails!
{[BankName, Microsoft.AspNetCore.Mvc.ModelBinding.ModelStateDictionary+ModelStateNode]}
{[BankAccount.BankName, Microsoft.AspNetCore.Mvc.ModelBinding.ModelStateDictionary+ModelStateNode]}
See,BankAccount is the model class,and BankName is a required property.I don't know why the property appears twice in ModelState dictionary,one with the model name(with the data entered) and one without the modelname(with null value)
Any idea why this is happening?
public class BankAccount
{
[DisplayName("")]
public int BankAccountId { get; set; }
[MaxLength(20, ErrorMessage = "")]
[Required(ErrorMessage = "")]
[DisplayName("")]
public string BankName { get; set; }
...
Here' the code OnPost() where the validation fails:
public async Task<IActionResult> OnPostAsync()
{
// TODO: Not ideal! But solves the problem of returning invalid model state.
ModelState.Remove("BankName");
if (!ModelState.IsValid)
{
return RedirectToPage();
}
_context.BankAccounts.Add(BankAccount);
await _context.SaveChangesAsync();
return RedirectToPage();
}
After searching a lot,I found a workaround,which isn't very ideal.That's to remove the additional property that has oddly been inserted in ModelState dictionary. I mean this line:
ModelState.Remove("BankName");
But that's not the right way.I'd like to figure out why it's happening?!
Here are two properties defined on the PageModel:
[BindProperty]
public BankAccount BankAccount { get; set; }
[BindProperty]
public BankAccount BankAccountEdit { get; set; }
One is used to insert new BankAccount and the other one is used to edit existing ones by clicking on a button from the table.
I figured out the the issue.The problem was that I have two properties of the same type(BankAccount class) in my page model,one for inserting new entity and the other one for editing existing entity all on the same page.
So to validate each form separately OnPost(),I used the following code:
public async Task<IActionResult> OnPostAsync()
{
var validateBankAccount = ModelState.GetFieldValidationState("BankAccount");
if (validateBankAccount ==
Microsoft.AspNetCore.Mvc.ModelBinding.ModelValidationState.Invalid)
{
return RedirectToPage();
}
_context.BankAccounts.Add(BankAccount);
await _context.SaveChangesAsync();
return RedirectToPage();
}

asp.NET MVC entity validation depends on other entities of the same type

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.

How to validate key constraints in ASP.NET MVC

I use the built in model validation which works great for specifying required fields and such but on my model I have specified key constraints so the combination of two columns are unique.
How should I validate for this so it doesn't throw exception if user tries to add duplicate?
Here is my model:
public class EmailFilter
{
public int ID { get; set; }
[Required]
[StringLength(100)]
[Index("IX_FilterAndEmail", 2, IsUnique = true)]
public string Email { get; set; }
//This is an enum
[Required]
[Index("IX_FilterAndEmail", 1, IsUnique = true)]
public EmailFilterType Filter { get; set; }
}
And my create controller method. I tried to add an error but I am not doing it right. It stops the exception happening but it just returns to the listview. I'm not sure what the right way to validate here is.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ID,Email,Filter")] EmailFilter emailFilter)
{
if (ModelState.IsValid)
{
if(db.EmailFilters.Any(x => x.Filter == emailFilter.Filter && x.Email == emailFilter.Email))
{
// This doesn't seem to do anything and returns to listview not create view
// "EFValidationSummary" is the id of my validation summary razor control
ModelState.AddModelError("EFValidationSummary", "This filter already exists");
return View(emailFilter);
}
else
{
db.EmailFilters.Add(emailFilter);
db.SaveChanges();
}
return RedirectToAction("Index");
}
return View(emailFilter);
}
How do I properly trigger an error and send back to the create page with the validation error displayed?
The first parameter of AddModelError() is the name of the property in your model. In your case, the error message would be displayed in the placeholder generated by
#Html.ValidationMessageFor(m => EFValidationSummary)
but your model does not contain a property named EFValidationSummary. In order to display validation messages in the placeholder generated by #Html.ValidationSummary(), you need to provide an empty string for the first parameter
ModelState.AddModelError("", "This filter already exists");

Asp.net MVC 3 - Data Validation

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.

Model to Controller / View Error Message

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

Categories

Resources