We have a ViewModel for "create" and one for "edit." The edit inherits from create so that we're sharing common fields. We are then using an #Html.EditorForModel("User") that uses the "create" as its model.
This is for editing users, so I need the password field to be required on create, but not required on delete. Thus, the create VM has Password with [Required] decorating it, while the edit VM has password property with no decoration, and is also declared with new (public new string Password {get;set;}).
This is almost exactly similar to this question:
MVC4 Conditional Required Annotation
For my situation, it's still requiring the field I believe due to the EditorTemplate using the create object as its model instead of the edit. I tried changing it from editorformodel to:
#Html.EditorFor(model=>model, "User")
in hopes that because edit is actually a "create" due to inheritance that it would work, but it'still barking at me for not providing the required field when I post.
Is there a way to accomplish what I'm attempting, or are my options to either remove the required and handle it server-side, or split the editor template into two templates?
You can create a custom attribute to drive your check on whether the password is required or not. When the submission happens to the server your custom attribute can check to see if the you are dealing with an Update or and Insert and then invalidate the model if it needs to.
Here are some resources on creating custom attributes and custom attributes with unobstrusive jquery validation
Happy Coding!!
Related
I have a model containing a property of HttpPostedFileBase type, and I have created a custom validation attribute which implements RequiredAttribute to make some validations. It works perfectly when you create the model. However I don't want to make any validation when you edit the model (optional HttpPostedFileBase property when you edit the model). How do I make it?
Your attribute is simple metadata added to a property of a class. This attribute has no information about what you do with the class, i.e. if you're using this class to edit or to create a new entity.
So, the answer is that you cannot do that directly in the attribute. So the only solution is to "bypass" the attribute where you're using it, if you're editing the value. There are several alternatives:
use two different models, one for editing, the other for creating. And decorate the property only in the model for creating
remove the validation, or the error, using some code to do it: for example, you can remove the property error from the ModelState in a post action for the Edit action.
Obviously the easiest is 1. You can use a base class with all the fields, but those which have different treatement, and then inherit it for creation or edition. It's not strange to represent the same data with different models when you use MVC: a model for viewing, a model for showing the editor, a model for receiving the result of an edition... so, using several different models is not a problem at all. You can use AutoMapper or ValueInjecter to simplify moving data between entities and models.
With MVC, when you use something like #Html.TextBoxFor(...) the control renders using property attributes from the model for things like validation.
It also uses the class's property name as the name of the rendered HTML control. This conflicts a little with our naming conventions so I'd like to be able to control the ID a bit more.
I've added the 'htmlAttributes:' to the helper, which does what I want, but I was wondering:
How does this impact MVC's ability to instantiate the model again
when the information is posted?
Is there a way to specify the control ID using property attributes in the model class?
Thanks,
Jacques
How does this impact MVC's ability to instantiate the model again when the information is posted?
The ID attribute has absolutely no impact on anything that is posted. The ID attribute is never used when submitting a form. The only requirement is that this attribute is unique throughout your entire DOM. It is the name attribute that is used by the model binder. You cannot change this attribute anyway using the htmlAttributes because this attribute is inferred from the lambda expression used as first argument and you shouldn't need to change it anyway, otherwise you could break the way the default model binder rehydrates your view models.
Is there a way to specify the control ID using property attributes in the model class?
Yes, but it could be a little more work. You could use custom editor templates for the standard types and a custom metadata aware attribute that will pass this additional metadata information to the custom editor template. If you are interested in the implementation specifics I could provide an example but first I have to understand why you need that.
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
We are relying heavily on client-side validation using MicrosoftMvcValidation.debug.js in the our current application implementation.
We have form elements and form validators being defined in the database and loaded from the database at runtime. We have viewmodel properties Answer1, Answer2, Answer3, etc., and up until now all fields were required, so we had the [Required] attribute on each of them, but now we need to apply this required annotation at runtime based on database settings since some of the questions are optional.
I don't want to do any reimplementation of validators themselves, I just want to either dynamically remove the [Required] attributes and/or their effects at runtime, or else dynamically add them at runtime.
Using ASP.NET MVC 2.
Add the [Required] attribute to any fields that could be required. As long as you don't bind a control client-side, you will bypass client validation without problems. On the server side post-back action, loop through the ModelState (which implements IDictionary) and clear the errors on the ModelState for the validators that you want to bypass.
foreach( var validator in ModelState){
if( validator.Key == "Validator_To_Bypass")
validator.Value.Errors.Clear();
}
Seems one can create a custom class that inherits ValidationAttribute that can determine at runtime how or whether validation is done. This is one way of accomplishing this requirement.
I have the following model:
Customer:
ID
Name
Address
Phone
Fax
I added an Edit view based on the above model from the controller. I modified the Edit view to only allow edit on the Phone and Fax field (deleted the rest). When I submit it I get an error. It works if I leave the Edit view untouched (5 fields). However I only want to allow change in the last 2 fields.
I am lost, please help. Thanks :)
If you are using the MVC ability to populate your entity/class i.e. your action sig looks like this:
ViewResult MyAction(MyObject object) {
...
Save(MyObject);
}
then you'll need to make sure you include the other field, non-editable, either as visible information or using Html.Hidden within the form scope to ensure you have a fully populated object. Remember, the web is stateless and the server has no idea which record you were editing unless it has the keys to do so retrospectively.
The other option would be to retrieve the original object (for which you'll still need the primary key) from the database, update the fields from your form data and then submit the changes. We'd need to know the specific error to be able to help further, the code you are using would also be a great help.
Without knowing more I would guess it has something to do with binding null to a non null property in your model. Can you give me more details on the model, the error.
If you are using the default mvc model binder then it will only bind the fields you submit. So either submit as hidden or dont use a model binder and manually map the variable from Request.Form into a copy of the model you pulled form the db.