Refresh ModelState to remove errors - c#

Refreshing the ModelState
Hi, I have a question about the ModelState in an ASP.NET MVC controller.
When the user selects a certain option from the view, the start date and end date for the "certification" will be set based on the other dates entered.
The problem with this is the certification dates come back as null and our CertificationMetaData class specifys the fields as [Required] so the ModelState is invalid as soon as the action loads.
Removing the ModelSate errors manually allows this to work but I was wondering if there is a better way to do this? Is there a way to refresh the ModelState? Should I make the fields not required? Or should I add a date value from the view with javascript?
public ActionResult Create(FormCollection fc, Certification certification, Absence absence)
{
if (certification.CertificationTypeID == 1)
{
certification.CertificationStartDate = absence.StartDate;
certification.CertificationEndDate = absence.StartDate.AddDays(7);
this.ModelState.Remove("CertificationStartDate");
this.ModelState.Remove("CertificationEndDate");
}
if (this.ModelState.IsValid)
{
// save
return RedirectToAction("Index");
}
return View();
}
Also as you can see I have hardcoded the ID value for the certification type. What is the best way to compare values with lookup table values? Is an enum the best way to go?
Thanks

The following approach refreshes the model state and allows you to keep your model design consistent with [required] attributes etc.
In my case I want my model to have a required field that normal level users using an API can't change, so I've done this:
ModelState.Remove("ChangeDate");
ModelState.Add("ChangeDate", new ModelState());
ModelState.SetModelValue("ChangeDate", new ValueProviderResult(club.ChangeDate, DateTime.Now.ToString(), null));
That way you don't need to remove your required fields, and you also don't need to supply a date in javascript.

Obviously this is a personal thing, but I wouldn't remove the error messages.
If I was going for the simple solution then I would remove the [Required] attribute and add validation code to the controller to add the error if the dates were missing or set them to the alternate value if it was the correct type.
If I was going for the more complex solution I would put the validation at the Model level. Possibly a base class or and interface that the model must implement. A ValidationHelper class with a static Validate(IValidate object) method that will inspect the ValidationAttributes and calls a Validate method on the Model. It would then return a collection of ValidationErrors. Then a custom ModelBinder would be written that understands the Model validation and maps these to ModelState errors.

Related

C# MVC/API Custom Validation Trigger - One Field Only

I have a single field for an API model that I want custom validation for through whatever method possible.
The solution I need is: On modelstate validation fail for that specific field - I want to run custom code to modify the value of that field.
Due to the codebase I'm working with some constraints:
The validation trigger code has to be inside the model or bound to it somehow.
It's not reasonable for me to create custom validator for the entire model.
It's not reasonable for me to put code in controller on !modelstate.valid
My problem was I didn't think you could mix and match annotations with custom validation. You can.
Make your class inherit IValidateableObject
public class MyClass : IValidateableObject
{
}
Add Validate Method - "FieldName" is your class variable being validated
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if(your_condition_is_invalid)
{
yield return new ValidationResult(
errorMessage: "your error message",
memberNames: new[] { "FieldName" }
);
}
}
Below not applicable to this problem specific problem but I thought to include incase there is a frontend component.
The downside is, according to the person I asked, if you are using for a webapp, there are cases where you need to write custom frontend validation.
It doesn't automatically mesh with default mvc frontend validation / jquery unobtrusive.
If you plan to do this for an app where you have strict frontend validation standards then be ready to write a validator for that field.

asp.net mvc ViewState implementation

I working on a web project where I first get data from the database and bind to the Html control. If there is a validation error I will send the same view back for rendering with the displayed validation errors. When the page comes up, there is an exception. I stepped through the code and found that the model was passed will null collection. Basically any property that was not binded to a textbox was changed to null. I was told not to use session or viewdata to keep temp storage. So I call a method SaveViewState where it save all the property value of the ViewModel property to a static variable like so
private static MyViewModel _viewModel;
private MyViewModel SaveViewModel(MyViewModel viewModel)
{
if (_viewModel == null)
{
_viewModel = new MyViewModel ();
}
if (!string.IsNullOrEmpty(viewModel.MyName))
_viewModel.MyName= viewModel.MyName;
if (!string.IsNullOrEmpty(viewModel.Number))
_viewModel.Number= viewModel.Number;
if (!string.IsNullOrEmpty(viewModel.Address))
_viewModel.Address= viewModel.Address;
if (!string.IsNullOrEmpty(viewModel.State))
_viewModel.State= viewModel.State;
}
It works but I think it is very inefficient and there must be a better way to implement ViewState in MVC with Session or ViewData or HiddenFields? By the way, I was told not to use those three.
Any help is appreciated. Thanks.
I am not sure if this solution is worse than using a session or hidden fields. In your action you should return the corresponding view with the same model that was posted. The ActionResult should be something like this:
public ActionResult SomePost(SomeModel model)
{
if (!ModelState.IsValid())
{
//error in validation
return View(model);
}
//post save redirect and stuff
return ... redirect?
}
The ModelState.IsValid() will test according to the DataAnnotations. Standard attributes like [Required], [MaxLength] etc. are available.
In this configuration, the use of a SaveViewModel function is not required. If your collection is null after post: re-query it, post it or fetch it from a ViewData like object.
There are good reasons not to use those three you mentioned, but if you know that reason you might want to consider it:
1) Use of session: will make scalability difficult because every request in a session must hit that specific server.
2) Hidden fields: Not really a problem IFF you realize the hidden field can be manipulated in a browser. So don't store ID's there
3) ViewData: basically breaks the MVC pattern; you can use it to store data but that's what a model is for. It totally legitimate to use ViewData from a filter. To provide some general functionality for example.

MVC Validation on HttpGet

I have a Search Form wired to an HttpGet method
[HttpGet]
public ActionResult Search(Filter filters){
{
...
}
What I would like to be able to do is modal validation, the way it is done in HttpPost. However, I do not want to use HttpPost method because I want to allow users to be able to bookmark their search results.
Filters is my dto.
Is there a way I can raise the validation in the HttpGet method? Like..
if (!filters.Name.HasValue)
{
this.ModelState.AddModelError("Name", "THis is a required Field...");
or use Data Annotations
public class Filter {
[Required]
string Name {get;set;}
...
Not sure if this is the correct way. Again, I am not sure which is the best approach. Any help/advice would be great.
Yes, this is fine.
Model binding and validation doesn't require the HTTP method to be a POST.
Try to use data annotations where possible. They're clean and elegant. Create your own if needed.
Remember that data-annotated validation should be simple; i.e. check to see if values are populated and meet the most basic of requirements (length, data type). After that more serious validation can take place (if needed).
You'll then need to return an adequate view for showing the user the search results or any problems with the search so that they can try again.
There is not much more I can add to answering your question. Your approach is fine.

UpdateModel without validation

Is there a possibility in ASP.NET MVC3 to set the properties of a view model from a FormCollection without invoking validation specified by validation attributes on the properties?
UpdateModel<T>(T model) also invokes validation.
The background:
I can only validate the model if a connection to the database is present, but this connection can only be established, if the data from one specific form field is correct (kind of an access code for each organisation). If the connection is not established, an exception is thrown.
When the data entered in this field is incorrect, I don't want to loose the values entered in all other form fields, but present the already entered values again to the user and give him a change to correct the errors.
So what I need is basically something like conditional validation or no validation by the model binder at all.
Is there anything like this built-in in ASP.NET MVC or do I need to write my own UpdateModel method, calling a (custom) model binder?
Why not pass the viewmodel into your method, rather than formscollection? That way you can do
[HttpPost]
public ActionResult Update(UpdateViewModel model)
{
if (!Model.IsValid)
{
return View(model);
}
}
So if the validation fails your user is going to be directed back to the Update view, with the model already populated from the information they submitted.
Now, in my opinion, having a validation attribute require a database connection, which in turn can throw exceptions is the wrong way to go about this. Those sorts of validation I move to a validation service, which is injected into the controller (and takes in the repository stuff it needs via DI as well). Each validation service will take in a view model and return a collection of ValidationResult instances, which I then attach to the model validation results via an extension method to the Controller class (both lifted from the Project Silk stuff MS P&P is pushing out)
This allows for easier testing as you can mock up the repository and have it return the correct results for testing ...

ASP.NET MVC Model confusion

Background
I'm learning the ropes around how to use ASP.NET MVC properly, and ran into this issue with models:
I have a model that describes a contact I can get that out of the form for creating a new contact, but say when we edit a form, I retrieve it from the repository, show the fields on the contact form and then get the contact object and send that to the model.
Problem
I have a business rule that some fields are not allowed to be edited after creation and other fields are only available after editing.
I receive a dirty object from the user (one with fields they should touch) and using the MVC Binding method (sspecifying the object in the method signature) the users inserts a non-editable field contact_dob.
Question
Should I instead retrieve the record again, overwrite only the fields I want to update and then send it to the database?
What's the best method when I don't want to retrieve the Entire object again from the database, do I just redo another EntityModel that's a lighter version of the main model and use that back and forth?
Am I going about this the wrong way? What are the best practices for limiting what users can edit?
I think you can build your model, the Contact class, and in the edit view you should allow only fields that can be edited, and hide or set as not editable the fields you don't want to be edited, then in your controller you'll get the original contact and update it with the values of the fields you allowed in the edit view like:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {
Contact contact = repository.GetById(id);
try {
UpdateModel(contact);
repository.Save(contact);
return RedirectToAction("Details", new { id=contact.Id });
}
catch(Exception ex) {
// Do something...
}
return View(contact);
}
It sounds like the best solution would be to use a custom ViewModel. This is an object that contains all the fields that you would want the user to submit to the controller.
You will need to reload the contact object from the database - I don't think you can get around that without opening yourself up to other issues.
public ActionResult Edit(ContactViewModel viewModel)
{
var contact = repository.GetContacts().WithId(viewModel.Id);
// Update the contact with the fields from the viewModel
repository.Save(contact);
}
You should use the EXCLUDE and INCLUDE constraints in Action method. This way your model will exclude unwanted fields during model binding.
public ActionResult Create([Bind(Exclude="contact_dob")] Contact contact)
{
_db.AddToContacts(contact);
_db.SaveChanges();
return RedirectToAction("Index");
}
The 'best practice' is to have validation done against your submitted model and not allow changes to certain fields. You can use JQuery / JavaScript to grey out textboxes that cannot be changed; as well as validation on the Model side to disallow changes to certain fields (by comparing them against what came from the database).
You can use Model Validation to disallow changes to certain fields. ASP.NET MVC 2 has this functionality. You don't even need to re-retrieve the object.
In the 'NerdDinner Walkthrough' (ASP.NET MVC 1.0), there's a walkthrough of Validation.

Categories

Resources