ModelState.IsValid is false because CreatedBy field is null - asp.net-mvc

I have an entity with, amongst others, the fields: CreatedBy, CreatedAt, ChangedAt
Now in the view, I do not want the user to fill these fields.
My approach was to fill them on the HTTP POST Action, before ModelState.IsValid check is made and before saving the data to the database.
However, ModelState.IsValid keeps returning false no matter what. What is the right way to implement this? Should I take the validation (ModelState.IsValid) from the POST action?

One problem, many solutions (from best to worst, in my opinion).
First solution
The best way would be to use a ViewModel (a class containing only the fields which must be edited by user and / or validated).
In this case, the CreatedBy, CreatedAt, ChangedAt fields would not appear in your ViewModel class.
Second solution
If you don't want ViewModel, you can put the "not mutable by user" fields as hidden fields in your view
#Html.HiddenFor(m => m.CreatedAt)
of course, hidden fields can be changed by user, so it's always an open door to unwanted datas...
Third solution
Clean ModelState from undesired errors before checking if it's valid (should become really boring if you've many fields concerned).
if (ModelState.ContainsKey("CreatedAt")) {
ModelState["CreatedAt"].Errors.Clear();
}
//then test for ModelState.IsValid()
Other solutions
WhiteList, BlackList for model binding, or... anything I forgot !

Many projects like to separate the View Model from the Domain Model. This allows you to create a View-Model class specifically tailored for the data you want to render and/or receive in a certain action while keeping the domain model correct/consistent.
In your View-Model class you would either not define any such property as the created date (since it is not supposed to be posted but is determined in the action). Or if you use one and the same View-Model for rendering and posting, and you want to render the date, you can make the date nullable (see Alexey's answer) on the View-Model while keeping it mandatory on the domain model.

DateTime is not nullable. If you want to keep those fields as null during model binding, if there is no values for them use:
Nullable<DateTime>
or shortcut:
DateTime?

Related

How page specific should a viewmodel in MVC be?

I've understood that a viewmodel in MVC is supposed to reflect data on a single page rather than objects in the model. But should the viewmodel correspond to the data you want to show on that page or to the data you want back from that page? If we for example look at a login page then I just want username and password back in the post, but I might need more variables than that when displaying the login page (previous error messages etc).
Should the viewmodel then just contain username and password as parameters and the rest of the variables end up in viewbags. Or should the viewmodel contain all values I want to show even though I'm only interested in a few of them in the response.
What is best practice when using viewmodels?
All data that somehow interacts between the html and your server should be in a ViewModel.
This allows you to perform formatting and such outside your html and inside your ViewModel properties.
However, if your page contains a lot of controls or data, you may want to split it into multiple ViewModels (example one for the Get and one for the Post).
The post model may contain only data that you entered and needs to be validated.
I think it's best to put everything in the view-model. This keeps the code cleaner and makes discovery and maintenance easier as well. The view-model should be your primary mechanism here.
I would say only properties you need, in your case username and password. If you want to display error messages then that's what ModelState is for. You can always append any error messages to your ModelState:
ModelState.AddModelError("PropertyName", "Error Text")
Beyond that let's say you have a form that contains a list of categories that you need to pick one category from a drop down. In this case I usually attach that list to my model even though the only thing being submitted is the actual selected value. But this is a matter of preference, meaning I could also set a ViewBag to contain this SelectList of categories and then bind that to your DropDownList. I suppose it's better to place this in a model because ViewBag is dynamic and you will have to cast anything in the ViewBag into it's underlying type on your views.

MVC required fields on optional object

I have a complex view model which has some subclasses. For the sake of a simple example, let's assume there's one subclass.
That subclass is displayed by rendering a partial view. The user can toggle that view in the interface, completely hiding the whole thing.
Now there are two valid input options:
The user chooses to hide the partial and doesn't fill in anything. The whole thing should be ignored.
The user chooses to view the partial, now he has to fill it in. Some of the fields are required, some are not.
What's a good way to handle this is MVC validation? I cannot mark the fields as Required, since the postback will post the empty values and the server side logic will say ModelState.IsValid is false beacuse there are fields missing.
Of course I can lose the [Required] attributes and do the checks manually myself, but I was wondering if there's no better way to get the same result.
The simplest way of doing this is like this ASP.NET MVC 3 Data Annotation: Add validation dynamically.
For a harder (a bit nicer) solution read this: DataAnnotations "NotRequired" attribute

How to handle hidden fields in MVC forms?

I have a FormViewModel that handles different fields. Many of them have not to be presented to the user (such as modified_date, current_user_id) so I am using hidden fields to respect the FormViewModel structure. When submitted they are passed to the controller's action and correctly saved to the DB but I'm asking: is it the best way to do in ASPNET MVC? I would have preferred to define them in FormViewModel and using only the fields to be modified instead of showing also the non-modifiable as hidden fields.
Is there a better way to do it?
If these fields are not being touched by the user than I would do this;
Create a FormViewModel with only the fields that are relevant. Also the primary key.
The primary key still needs to be on the page me thinks.
Then in the controller you accept the FormViewModel as the argument, you then load the actual model and update, validate fields as required and save the model.
The above is simplistic and you'll have more layers but you should get the idea
I think you can do a few things to make your life a little easier:
Let the URL (and the routing mechanism) give you the id (the primary key of whatever you are trying to edit)
You can have a URL like '/Student/Edit/1' Routing will ensure that your Action method gets the id value directly.
Have 2 action methods to handle your request. One decorated with [HttpGet] to render the initial form to the user (where you just retrieve your object from the repository and pass it on to your View) and a [HttpPost] one to actually handle the post back from the user.
The second method could look something like:
[HttpPost]
[ActionName("Edit")]
public ActionResult EditPost(int id) {
...your code here...
}
Retrieve the actual record from the repository/store based on the id passed in.
Use the UpdateModel function to apply the changes to the database record and pass on the record back to your repository layer to store it back in the database.
However, in a real world application, you will probably want separation of concerns and decoupling between your repository and your view layer (ASP.NET MVC.)
If they are part of the model, the method you are using is perfectly fine. You even have a helper method in HtmlHelper.HiddenFor to output the hidden field for you. However, if the values are something like modified date or current user, you'd might be better suited passing those along from your controller to a DTO for your data layer. I'm making some assumptions about what you're doing for data access, though.
The risk with storing data which shouldn't be modified in hidden fields is that it can be modified using a browsers built in/extension developer tools. Upon post these changes will be saved to your database (if that's how you're handling the action).
To protect hidden fields you can use the MVC Security Extensions project https://mvcsecurity.codeplex.com.
Say the field you want to protect is Id...
On you controller post method add:
[ValidateAntiModelInjection("Id")]
Within your view add:
#Html.AntiModelInjectionFor(m => m.Id)
#Html.HiddenFor(m => m.Id)
On post your Id field will be validated.
Create a FormViewModel with only the fields that are relevant. Also the primary key.
The primary key still needs to be on the page me thinks.
Then in the controller you accept the FormViewModel as the argument, you then load the actual model and update, validate fields as required and save the model.
The above is simplistic and you'll have more layers but you should get the idea

mvc modelbinding

I have an Edit action/view for my User object, but only want a few fields to be editable.
I've set up the view to bind to the User object, and am using Html.EditorFor() for the few fields that I want to be editable.
I noticed in my User object on Post:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditUser(Mynamespace.User user)
{ }
that only the fields that I provided .EditorFor() controls for actually have any data.
I tried using Html.Hidden(Model.ID) for one of the fields that i didn't want to be editable, but it is null in the new User object created from model binding.
So, my question- How do I bind where only a couple of the fields should be editable?
Thanks!
It sounds like you probably want to start thinking about using a View Model that is specific to the form/input that you're dealing with. But in the short term, ....
You could bind to a FormCollection parameter instead and copy the values manually, OR...
you can use the TryUpdateModel method to populate this existing user object with the new data.
Here's the documentation for TryUpdateModel:
http://msdn.microsoft.com/en-us/library/dd470756.aspx
It's still possible for malicious users to send phony form-values that map to real properties on your model, so to protect against this (like an employee changing his salary property with a simple form hack) you can introduce an interface that contains the white list properties that you allow.
Here's an example:
public interface IUserEditableFields
{
string Username {get;set;}
string Email {get;set;}
}
//... in the controller action
if(TryUpdateModel<IUserEditableFields>(user)) {
//validation passed
//only Username and Email were editable
}
This is a good resource on how to do this:
http://css.dzone.com/news/aspnet-mvc-think-before-you-bi
Are you using the strongly-type helper for the hidden field or is it exactly like you've typed. If you've got it exactly as typed, then the name of the hidden field is the value of the id, not the name of the property on the model (ID). You might want to change it to:
<%= Html.Hidden( "ID" ) %>
or (if using strongly-typed helpers)
<%= Html.HiddenFor( m => m.ID ) %>
Ben's answer is largely correct, in that a ViewModel might be more appropriate, and short of that, TryUpdateModel can be used. However, I add that in that case, rather than requiring the domain object to implement a new interface, you use the overload TryUpdateModel<T>(T, string[]), which allows you to whitelist the updateable properties in a string array by name.

How do you ignore/persist values in MVC when your view-model doesn't have as many fields as your domain model?

I have a site where I'm using fluentNhibernate and Asp.net MVC. I have an Edit view that allows user to edit 8 of the 10 properties for that record (object). When you submit the form and the Model binds, the two un-editable fields come back in the view-model as Empty strings or as default DateTime values depending on the type of property.
Because I'm also using AutoMapper to map my view-model to my Domain Entity, I cannot just load a fresh copy of my object from the database and manually set the 2 missing properties. Whats the best way to persist those fields that I don't want edited?
One way that does work is to persist the values in hidden Input fields on my View. That works but feels gross. I appreciate any recommendations. Is there a way in my AutoMapper to configure this desired functionality?
UPDATE:
Ok, So I guess I'm not trying to ignore the fields, I'm trying to make sure that I don't persist null or empty string values. Ignoring the fields in AutoMapper does just that, they get ignored and are null when I attempt to map them before Saved to my repository.
The asp.net mvc DefaultModelBinder is extensible, and you can override it to create your own binding schema. But this will involve more work than two "hidden Input fields", which , in my point of view, is not that gross.
You can tell Automapper to ignore the 2 properties:
Mapper.CreateMap<Source, Destination>()
.ForMember(dest => dest.SomeValuefff, opt => opt.Ignore());
Possible related question.
Can you use the AutoMapper.Map overload that also accepts TEntity?!
entity = Mapper.Map(viewmodel, entity);
As long as you do not have the properties on your viewmodel, it won't change the values on your entity. It takes the entity being passed in and applies only the properties from the viewmodel back to the entity.

Resources