In the simple blog engine I’m building, I encountered a scenario where I wanted to display different UI elements depending on whether the user was logged in:


When the user is authenticated, their name and email is known, so it’s unnecessary to display them on the comment input form. While it would be possible to hide just those fields, I decided to make separate partial views and display them in the Post view with the following code:
<% if (Model.AllowComments) { var commentControlName = Request.IsAuthenticated ? AuthenticatedCommentFormControl" : "CommentFormControl"; Html.RenderPartial(commentControlName, new DotBlog.Models.ViewModels.CommentViewModel(Model.PostId)); } %>
This is the view model I used for both partial views:
public class CommentViewModel { ... [Required] [StringLength(50)] [DisplayName("Name")] public string CommenterName { get; set; } public DateTime Date { get; set; } [Required] [StringLength(100)] public string Email { get; set; } [StringLength(100)] [DisplayName("Web Site")] public string WebSite { get; set; } [Required] [StringLength(1024)] [DisplayName("Comment")] public string CommentText { get; set; } ... }
As you can see, I’m using data annotations to enforce required fields and string lengths. The problem is, even though the name and email aren’t always displayed, they are still required. I needed a way to validate certain fields conditionally. Here are the options I came up with:
- Stop using data annotations and find a different solution for validation
- Use two different view models: one for each partial view
- Use actual conditional data annotations, like the library built by Simon Ince.
- When the form is posted, remove the fields from the model state so they’re not validated.
Let’s look at each of these individually:
Stop Using Data Annotations
Data annotations are not the only way to specify validation rules, but they’re easy to implement. xVal was fine for ASP.MVC 1.0, but is now deprecated. Custom validation code with ModelState.AddModelError() is flexible, but requires extra work.
Use Two Different View Models
Since I’m using two partial views for the comment form (one for authenticated users and one for guests), I could use a dedicated view model for each. One would omit the data annotations on name and email and therefore not cause any validation problems. This was my original implementation, but lead to unnecessary code duplication and other design problems.
Use Conditional Data Annotations
Simon Ince has built a cool library for conditional annotations that allows you to write code like this:
public class ValidationSample { [RequiredIf("PropertyValidationDependsOn", true)] public string PropertyToValidate { get; set; } public bool PropertyValidationDependsOn { get; set; } }
Conditionally Remove Fields from the Model State in the Controller
In the end, this is the solution I went with. The controller executes this code when the form is posted:
if (Request.IsAuthenticated) { ... // We don't need to validate user fields if user is logged in. ModelState.Remove("CommenterName"); ModelState.Remove("Email"); }
By removing the fields from the model state, it won’t be invalid when they are missing. This method is simple and avoids adding additional dependencies.
I posted a solution that extends your model state cleanup option:
http://www.compiledthoughts.com/2011/02/aspnet-mvc-excluding-model-validation.html
Nicely done!
I agree – well done
Just what I’ve been looking for
Bit late to the party here… I’ve run into a similar problem recently, We may have many data annotations on a particular view model property such as Required, StringLength, Email etc. Making them all conditional would be a mess. I’m currently using the approach of using multiple view models. I honestly think this is a better approach in non-trivial scenarios. I’ve been following the philosophy that view models should be used as intended, that is, specific to a view. So I don’t share view models or at least I rarely do.
thedevpath – you make a good point. Actually, I would no longer recommend the approach I use in this article. I would go with a more powerful validation library like Fluent Validation for .NET instead. http://fluentvalidation.codeplex.com/
Thanks Andy, ran into the exact same issue and you saved me some time!