Each time I start working on a new ASP.NET MVC web application, I'm not sure whether or not to use DataAnnotations validation. Something about it feels wrong.
For example, let's say I have a UserService which is passed a CreateUserModel from the Create action of the AccountController. To ensure the user always supplies a name, I set the model's Name property to have the [Required] attribute. I'm now safe in the knowledge that the model binder won't ever give me a CreateUserModel unless it has a name.
My problem is that for my UserService to be a reusable component of my system, it can't rely on the fact the layer above is supplying valid data, and surely must also validate this data. The need for this is highlighted further when you consider that you may want to write a web service that fully reuses the UserService (and wouldn't have the model binder to do all the data annotation validation for it).
So my question is: What is the best practice for this situation? Validate with data annotations and repeat that validation in the services? Validate only in the services and throw exceptions? A mix of both?
I hope my question isn't too subjective, I'm mainly trying to establish a consensus on whether moving the validation to data annotations is going to end up biting me in the end.
I perform all my validation in the service layer, using a combination of manual validations (if x == y) and using Data Annotations.
To use Data Annotations in your service layer, you have to manually use the Validator class using the TryValidateObject() method. A good example of this can be seen here.
You then have to pass your validation errors down from your service layer to your controller, and have your controller add each error to the Model state error list.
You are right, you should disable the validation on the controller and validate in the service layer. You can still use DataAnnotations if you want to. The service layer can throw an exception with the validation messages, the controller can catch that exception and add the validation messages to the ModelState. You can avoid doing that for each action by handling the validation exception on the OnException method of the controller.
I would personally don't mind that things are validated twice, as long as the logic is defined in one single place, which is clearly the case in your situation. I'm not experienced enough to say much about MVC, but I can imagine that throwing exceptions from the service layer just won't give a user experience (UX) that is as good as what MVC can give you when validating (it can for instance show an error message next to the textbox that is invalid. It is much harder to do that when throwing exceptions from your service layer). When the UX is the same, do your validation only in the service, otherwise do it in both layers.
Related
First of all, I have to say that I understand how Data Annotation -based Model Validation works in ASP.NET MVC4 and I have it successfully implemented with DataAnnotationsModelValidatorProvider. So I don't need assistance on setting it up.
But when it comes down to HtmlHelpers, I'm struggling with trying to figure the context of the error message. And by saying context, I mean which error we're talking about. Which Attribute returned the error?
What I can get, is the Key for the error and the current ErrorMessage but programmatically, there's nothing, that at least I'm aware of, that would communicate which error we're talking about. Whether it was Required attribute or some other attribute, there's not way that I can find how to distinguish them.
Let's open the scenario a little bit. I have custom HtmlHelpers to render ContentEditable elements. For example Html.ContentEditableValidationMessageFor(m => m.firstName);. It will output something like this:
<span contenteditable="true" data-valmsg-for="firstName" data-valmsg-replace="Please provide first name" class="field-validation-error">Please provide first name</span>
Now, I do have a jQuery plugin to handle and persist the changes in the contenteditable element and it will persist them into the backend. However, the UI has nothing that would say which error message we're talking about. Humans can easily see it's the RequiredAttribute, but programmatically there's no data to differentiate it from some MinLengthAttribute for example.
In this scenario, if I would simply use the data-valmsg-for="firstName" as the key for the localization, that'd return the same error message for all the errors concerning the same property.
To Round it Up
What would be the Best Practise, when ModelState is available, to emit a unique ID for ModelError? Considering I'm using ASP.NET MVC4 and DataAnnotationsModelValidatorProvider.
I can think of tons of ways to "Hack it Together" but I would like to use the ModelState and whatever MVC provides. If it all goes down to writing a custom ModelValidatorProvider, then I'm all open for it. As long as it is the best and most sustainable way of going about it. I'm all for Doing More Now and Less Later than Hacking it Now and Hacking it Forever to Keep It Working
Can you give some context around the need to know which rule triggered the validation error, could it be a case of you trying to do something you shouldn't have too?
In general I use FluentValidation (http://fluentvalidation.codeplex.com/wikipage?title=mvc) in place of Data Annotation validation for many reasons, de-cluttering models, unit testing validation logic, allowing vastly more complex validation that include business logic. If your free to use 3rd party libraries I'd give it a look as it has always solved any validation problems I've had in the past.
It lets you write c# code that deals with your model validation via a fluent API. It has an MVC extension that wires everything up for you so other than creating the models validation class there is little impact from then on. An example for your code snippet above would be...
RuleFor(modelname => modelname.FirstName).NotEmpty().WithMessage("lease provide first name");
Even implementing ModelValidatorProvider will not help, it is just a mechanism to provide ModelValidators based on Model Metadata. When during model binding process in a controller action ModelValidators are being invoked the result is just ModelValidationResult which only contains MemberName and a text Message.
I think there is a dirty way to find out which ModelValidator is failed by checking the error message like this:
var modelErrors = ModelState.Where(m => m.Value.Errors.Count > 0).Select(m => new { Name=m.Key , Errors=m.Value.Errors});
by checking ErrorMessage of Errors for each key in modelErrors against ValidatorProvider error messages you can find out the error belongs to which Validator.
Here's the scenario:
ASP.NET MVC2 Web Application
Entity Framework 4 (Pure POCO's, Custom Data Context)
Repository Pattern
Unit of Work Pattern
Dependency Injection
Service Layer mediating Controller -> Repository
So basically, all the cool stuff. :)
Flow of events for a basic UI operation ("Adding a Post"):
Controller calls Add(Post) method on service layer
Service layer calls Add(T) on repository
Repository calls AddObject(T) on custom data context
Controller calls Commit() on Unit of Work
Now, i'm trying to work out where i can put my validation.
At this stage, i need two types of validation:
Simple, independant POCO validation such as "post must have a title". This seems a natural fit for Data Annotations on the POCO's.
Complex business validation, such as "cannot add a comment to a locked post". This can't be done by Data Annotations.
Now, i have been reading "Programming Entity Framework, Second Edition" by Julie Lerman (which is excellent BTW), and have been looking into hooking into the SavingChanges event in order to perform "last-minute" validation. This would be a nice way to ensure validation always happens whenever i do "something" (add, modify, delete), but it's also a little late IMO (as the items are already in the state manager) - so what can i do if validation fails, remove them?
I could of course make my POCO's implement an interface (say "IValidatable"), and call a method on this interface during this event.
But this seems "too late" for business validation - is this the consensus?
I'm basically looking for guidance here, i'm trying to design a re-usable, intelligent validation scheme for complex business logic, given my above architecture.
Another curve-ball for you - as you know, POCO's with EF mean the POCO's have all the properties on the DB - so i might have a "PostID" property, with get/set accessors (as EF needs to get/set these properties).
But the problem is, "PostID" is an identity column, so how do i protect the field from being explicity set? E.g if i (for some reason) do the following:
var post = service.FindSingle(10);
post.PostId = 10;
unitOfWork.Commit();
This will throw a SqlException. How can i prevent this? I can't "hide" the property (make it private, or even internal) as the POCO's are in a seperate assembly to the Repository.
A note on validation - i'm planning to create custom exceptions (deriving from Exception). So when validation fails, i need to throw these exceptions.
That way, i can code something like this on my controller:
[HttpPost]
public ActionResult AddPost(Post post)
{
try
{
IUnitOfWork uow = new UnitOfWork();
postService.Add(post);
uow.Commit();
}
catch(InvalidPostOperation ipo)
{
// add error to viewmodel
}
}
Will i have to manually do validation on the service layer everytime i do an Add? Then how can i handle Save? (as this is on the Unit of Work, not the service layer).
So to prevent this from being a "all over the place" question, here are my questions:
Simple POCO validation - should this be done with Data Annotations? Pros/cons/gotchas?
Under what circumstances (if any) should we be hooking into the SavingChanges event of the EF Data Context in order to provide validation?
Where should i be performing complex business validation? In the service explicity, or a method on the POCO's (which i can call from service). How can i create an intelligent/reusable scheme?
How can we "hide" auto-generated properties of POCO's from being tampering with?
Any thoughts would be most appreciated.
Apologize if this post is "too long", but it's an important issue and one that can be solved in many ways, so i wanted to provide all the info in order for the best possible answer.
Thanks.
EDIT
The below answer is helpful, but i'm still (ideally) looking for more thoughts. Anyone else?
Well like you said, DataAnnotations is not appropriate for all situations. Cons are mainly complex validation (multiple property and multiple property different object) in my experience.
If i were you, i would leave business/domain validation out of the Data Layer (EF) as much as possible. If there is a Data Layer validation scenario, then fine (eg. validating complex parent/child relationships - this is purely DB stuff).
Yes, the complex business validation should be in the Service Layer or in the Model Objects (attached, via partial classes or some inheritance approach: interfaces/derived classes). There's debate about this between ActiveRecord people, Repository Pattern people and DDD people, but go with what works for you, is simple and will enable rapid deployment and low cost application maintenance. This is a simple example of how you might attach more complex validation to domain objects yet is still compatible with the DataAnnotations interface and thus is 'MVC friendly'.
Good question. -one i have not found a solution i'm 100% happy with yet. I have played with the idea of private setters and it's not great. Have a quick read of this summarized Evans DDD book. It's great quick read and it might provide some insight about the purpose and difference between Model Objects and Value Objects. This is where i think object design will mitigate the problems your having with the property "tampering" (as you call it) but without fixing the property visibility. Ie, another solution might lie elsewhere. Hope this helps.
Hey, probably a bit late but here goes anyway...
It all depends on your architecture, i.e. Is there a logical seperation, in your application: UI, Service Layer, Repository Layer. If you are hooking onto the Save event, how exactly will that be done? From what I observed you would be calling the repository Layer for Persistance only right? However you are hooking onto the save event, giving control back to the Service Layer/ Business Layer whatever then forcing the save through right?
I personally feel the Service layer/ Business Layer should take care of it in completion then say, hey mr repo layer -> save this object.
With regards to validation, Data Annotations should be used with the UI, so simple valiation like [Required] etc, this will be helpful with the Client Side validation but complex business logic or complex validation should be hooked into the service layer/ business layer, that way it is reusable across all entities/ objects/ POCOS etc.
With regards to preventing certain private fields not being tampered with... only allow your service layer/ business layer to actually set the object that will be persisted (yes i mean :) ...) hand coding it, I felt this was the safest option for me anyway, as I will simple do:
var updatedpost = _repo.GetPost(post.postid);
updatedpost.comment = post.comment;
updatedpost.timestamp = datetime.now;
Kind of wasteful but that way your buseinss layer takes control, however this is just my experience I may be wrong, I have read a lot into model binding, validaiton and other stuff however there seemed to be cases where things never work as expected e.g. [Required] attribute (see Brad WIlson's) post.
The DataAnnotations validation happens in the default model binder and most of the examples I've seen uses the Model.IsValid in the Controller to verify if a model is valid or not. Since my controller action calls a business layer method and I like to validate the entity there:
Do I have to explicitly switch off
the model binder validation?
How do I validate the entity in the
business layer. In other words, how
do I trigger validation given an
object?
Also, I am using View Models. Do I
add the validation attributes to the
view model? If so, since View models
are being tied to the UI, what about
validation at the business layer??
I'm gonna start by answering your question #3: yes, when using view models, add Data Annotation validation attributes right on the properties on your view model. As you pointed out, the view models are tied to the UI so they have presentation concerns and the validation is strictly for UI input validation. The validation attributes you apply here will be automatically invoked by the framework and you can check ModelState.IsValid in your controller (which you also pointed out).
In reference to validating objects in your business layer, there are numerous ways to do this. For example you could also use data annotations on your business layer domain model entities as well. You could also use other frameworks like Enterprise Library validation application block, Fluent Validation, etc. But in this case, you're probably going to be making an explicit call to validate your domain objects (and each of these frameworks has their own mechanism for doing so). I'm presuming your mapping between your view models and domain models (probably with something like AutoMapper) given your description above.
Having said all that, in reference to your question #1, I would not switch off model binder validation. Let that performance the validation on your view models as normal. Map your view models to your domain model classes. Then feel free to perform an additional layer of business object validation for your domain model. You may not even doing this validation in the MVC project - this might be encapsulated in a business layer that you have somewhere else in your app.
When I started using xVal for client-side validation, I was only implementing action methods which used domain model objects as a viewmodel or embedded instances of those objects in the viewmodel.
This approach works fine most of the time, but there are cases when the view needs to display and post back only a subset of the model's properties (for example when the user wants to update his password, but not the rest of his profile data).
One (ugly) workaround is to have a hidden input field on the form for each property that is not otherwise present on the form.
Apparently the best practice here is to create a custom viewmodel which only contains properties relevant to the view and populate the viewmodel via Automapper. It's much cleaner since I am only transferring the data relevant to the view, but it's far from perfect since I have to repeat the same validation attributes that are already present on the domain model object.
Ideally I'd like to specify the Domain Model object as a meta class via a MetaData attribute (this is also often referred to as "buddy class"), but that doesn't work since xVal throws when the metadata class has properties that are not present on the viewmodel.
Is there any elegant workaround to this? I've been considering hacking the xVal sourcecode, but perhaps there is some other way I have overlooked so far.
Thanks,
Adrian
Edit: With the arrival of ASP.NET MVC 2, this is not only a problem related to validation attributes anymore, but it also applies to editor and display attributes.
This is the quintessential reason why your input screens should not be tightly coupled to your model. This question actually pops up here on the MVC tag about 3-4 times a month. I'd dupe if I could find the previous question and some of the comment discussion here is interesting. ;)
The issue your having is you're trying to force two different validation contexts of a model into a single model which fails under a large amount of scenarios. The best example is signing up a new user and then having an admin edit a user field later. You need to validate a password on a user object during registration but you won't show the password field to the admin editing the user details.
The choices for getting around these are all sub-optimal. I've worked on this problem for 3 projects now and implementing the following solutions has never been clean and usually frustrating. I'm going to try and be practical and forget all the DDD/db/model/hotnessofthemonth discussions everybody else is having.
1) Multiple View Models
Having viewmodels that are almost the same violates the DRY principal but I feel the costs of this approach are really low. Usually violating DRY amps up maintenance costs but IMHO the costs for this are the lowest and don't amount to much. Hypothetically speaking you don't change how max number characters the LastName field can have very often.
2) Dynamic Metadata
There are hooks in MVC 2 for providing your own metadata for a model. With this approach you could have whatever your using to provide metadata exclude certain fields based on the current HTTPRequest and therefore Action and Controller. I've used this technique to build a database driven permissions system which goes to the DB and tells the a subclass of the DataAnnotationsMetadataProvider to exclude properties based values stored in the database.
This technique is working great atm but the only problem is validating with UpdateModel(). To solve this problem we created a SmartUpdateModel() method which also goes to the database and automatically generates the exclude string[] array so that any non-permissisable fields aren't validated. We of course cached this for performance reasons so its not bad.
Just want to reiterate that we used [ValidationAttributes] on our models and then superceeded them with new rules on runtime. The end result was that the [Required] User.LastName field wasn't validated if the user didn't have permission to access it.
3) Crazy Interface Dynamic Proxy Thing
The last technique I tried to was to use interfaces for ViewModels. The end result was I had a User object that inherited from interfaces like IAdminEdit and IUserRegistration. IAdminEdit and IUserRegistration would both contain DataAnnotation attributes that performed all the context specific validation like a Password property with the interfaces.
This required some hackery and was more an academic exercise than anything else. The problem with 2 and 3 is that UpdateModel and the DataAnnotationsAttribute provider needed to be customized to be made aware of this technique.
My biggest stumbling block was I didn't ever want to send the whole user object to the view so I ended up using dynamic proxies to create runtime instances of IAdminEdit
Now I understand this is a very xVal specific question but all of the roads to dynamic validation like this lead to customization of the internal MVC Metadata providers. Since all the metadata stuff is new nothing is that clean or simple to do at this point. The work you'd have to do to customize MVC's validation behavior isn't hard but requires some in depth knowledge of how all of the internals work.
We moved our validation attributes to the ViewModel layer. In our case, this provided a cleaner separation of concerns anyway, as we were then able to design our domain model such that it couldn't get into an invalid state in the first place. For example, Date might be required on a BillingTransaction object. So we don't want to make it Nullable. But on our ViewModel, we might need to expose Nullable such that we can catch the situation where the user didn't enter a value.
In other cases, you might have validation that is specific per page/form, and you'll want to validate based on the command the user is trying to perform, rather than set a bunch of stuff and ask the domain model, "are you valid for trying to do XYZ", where in doing "ABC" those values are valid.
If ViewModels are hypothetically being forced upon you, then I recommend that they only enforce domain-agnostic requirements. This includes things like "username is required" and "email is formatted properly".
If you duplicate validation from the domain models in the view models, then you have tightly coupled the domain to the UI. When the domain validation changes ("can only apply 2 coupon per week" becomes "can only apply 1 coupon per week"), the UI must be updated. Generally speaking, this would be awful, and detrimental to agility.
If you move the validation from the domain models to the UI, you've essentially gutted your domain and placed the responsibility of validation on the UI. A second UI would have to duplicate all the validation, and you have coupled two separate UI's together. Now if the customer wants a special interface to administrate the inventory from their iPhone, the iPhone project needs to replicate all the validation that is also found in the website UI.
This would be even more awful than validation duplication described above.
Unless you can predict the future and can rule out these possibilities, only validate domain-agnostic requirements.
I don't know how this will play for client-side validation, but if partial validation is your issue you can modify the DataAnnotationsValidationRunner discussed here to take in an IEnumerable<string> list of property names, as follows:
public static class DataAnnotationsValidationRunner
{
public static IEnumerable<ErrorInfo> GetErrors(object instance, IEnumerable<string> fieldsToValidate)
{
return from prop in TypeDescriptor.GetProperties(instance).Cast<PropertyDescriptor>().Where(p => fieldsToValidate.Contains(p.Name))
from attribute in prop.Attributes.OfType<ValidationAttribute>()
where !attribute.IsValid(prop.GetValue(instance))
select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(string.Empty), instance);
}
}
I'm gonna risk the downvotes and state that there is no benefit to ViewModels (in ASP.NET MVC), especially considering the overhead of creating and maintaining them. If the idea is to decouple from the domain, that is indefensible. A UI decoupled from a domain is not a UI for that domain. The UI must depend on the domain, so you're either going to have your Views/Actions coupled to the domain model, or your ViewModel management logic coupled to the domain model. The architecture argument is thus moot.
If the idea is to prevent users from hacking malicious HTTP POSTs that take advantage of ASP.NET MVC's model binding to mutate fields they shouldn't be allowed to change, then A) the domain should enforce this requirement, and B) the actions should provide whitelists of updateable properties to the model binder.
Unless you're domain is exposing something crazy like a live, in-memory object graph instead of entity copies, ViewModels are wasted effort. So to answer your question, keep domain validation in the domain model.
I understand annotating class properties with the basic required and minimum length and getting all the benefits of the asp.net mvc server side and client side validation.
However does anyone have a link that shows how you combine this 'base' validation with more complex business rules. How would I run business rule functions, such as for example, has the customer ordered anything in the last year (database hit required) and still use the same DataAnnotation and mvc validation plumbing?
Goal : Don't want two ways of generating and outputting validation methods.
From http://msdn.microsoft.com/en-us/library/dd901590%28VS.95%29.aspx:
To create customized validation checks, you can either create a class that derives from the ValidationAttribute class or create a method that performs the validation check and reference that method when applying the CustomValidationAttribute to the data member. When you create a class that derives from ValidationAttribute, override the IsValid method to provide the logic for your customized validation check.
There appears to be example code there.
Data Annotation run before your action is invoked. Then, regardless whether the validation succeded or not, the action is still called. If the DA detected invalid data, your ModelState will be invalid.
Once here, you can still do any validation you want, for your business rules, as you would normally do without the data annotation, if you want to. In your action, you can add errors to the ModelState even if the Data Annotation validation passed.
In this case, you add your errors with ModelState.addError, and those errors are added to any error provided by the DA. So in your View it doesn't matter where the error comes from.
Or, if your rules are general, you can write your own annotation tags. The Data Annotation thing is distributed with its source, so you have full control on it.
You could use VAB (Application Validation Block) from the Enterprise Library 5 of Microsoft that actually based on the DataAnnotations class but u do your complex bussiness logic very easily through configuration...
i'd suggest you check it out...
Have a look at following article, where you can use DataAnnotations Multiple Times On Same Field, Compare N number of properties and N number of values....
http://www.codeproject.com/KB/validation/MultipleDataAnnotations.aspx