I am building an ASP.NET MVC project and going for the following Architecture:
Making a mixed Validation could be also useful, so mixing DataAnnotations with custom validations logic
This may be helpful http://www.devtrends.co.uk/blog/the-complete-guide-to-validation-in-asp.net-mvc-3-part-2
I consider your approach to be good. Mapping one set of models to another could bring some bugs.
The code you are looking for is:
using System.ComponentModel.DataAnnotations;
var context = new ValidationContext(model, serviceProvider: null, items: null);
var results = new List<ValidationResult>();
var isValid = Validator.TryValidateObject(model, context, results);
if (!isValid)
throw new Exception("Model is not valid because " + string.Join(", ", results.Select( s => s.ErrorMessage).ToArray()));
For details see http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.validationcontext.aspx or http://odetocode.com/blogs/scott/archive/2011/06/29/manual-validation-with-data-annotations.aspx
My approach to this by fast thinking is to do something like that. In business layer create
public class ValidationMessage
{
public ValidationMessage(string message, ValidationMessageType messageType)
{
Message = message;
MessageType = messageType;
}
public string Message { get; private set; }
public ValidationMessageType MessageType { get; private set; }
}
public enum ValidationMessageType
{
Info,
Warning,
Error,
}
Now having a service example
public interface ISomeService
{
List<ValidationMessage> Edit(SomeModel item);
}
Now in the controller you call the service and pass the validation messages to the view. It may be necessary to use ViewBag and pass the whole list. On the view you can highlight Info, Warning, Error. For example you could return some success message with Info type, or nothing at all and in the controller create success message.
Generally this approach is more coding, but more flexibility. Ideally service would validate everything, but for smaller projects to avoid validation duplication, as Henk Mollema stated in his answer, you could do user input validation through ViewModel and in service just validate just critical business rules.
ValidationMessageType may be an overkill as well, so it's possible to return just List from the service as error list and the empty list would mean success.
I usually keep my view models in the Web project and do the input validation in the controller using the ModelState
property. If this succeeds, I map them to domain models (which live in the Core layer) and send those to my services in the Service (could also be Core) layer. The service layer validates business rules and if it succeeds it calls a repository to perform the desired action and returns the result of the operation to the controller.
Keeping your view models in the Web project also allows you to use MVC validation attributes such as RemoteAttribute.
I'm not saying that your design smells, but I do think it's good to separate presentation logic from your Core layer.