MVC Validation: Service Layer or Data Annotations - asp.net-mvc

I hope this isn't terribly subjective, but when it comes to validating business logic, I see two paths that, unless I'm mistaken, deliver pretty much the same result:
Use a service layer where all validation on your models is performed (ref: http://www.asp.net/mvc/tutorials/older-versions/models-%28data%29/validating-with-a-service-layer-cs)
Decorate your models with Data Annotations
In the first instance, the model is a dumb container for data, and in the second, the model knows about its valid state. Above and beyond that, is there nuance between the two that I'm missing? Should one be used over the other in some instances?
Thanks,
Chris

In my opinion, you could keep the basic validation (required fields, regex fields, comparative fields etc...) on your Model (InputModel) with Data Annotations or Fluent Validation, and your bussiness validation in service layer. I think the Annotations is much more to create a screen validation and inputs to server side than business validation. If you keep the business at the service layer you must remember to create a ModelState Wrapper to integrate it with Asp.Net MVC, and show it on the view.
Take a look at a samepl of ModelState Wrapper:
public class ModelStateWrapper : IValidationDictionary
{
private ModelStateDictionary _modelState;
public ModelStateWrapper(ModelStateDictionary modelState)
{
_modelState = modelState;
}
#region IValidationDictionary Members
public void AddError(string key, string errorMessage)
{
_modelState.AddModelError(key, errorMessage);
}
public bool IsValid
{
get { return _modelState.IsValid; }
}
#endregion
}

They are not mutually exclusive, you can use attributes for "static" rules, and service layer validation for "dynamic" rules (e.g. check for uniqueness).
Quoting the tutorial you referred to:
In this tutorial, you learn how to move your validation logic out of
your controllers and into a separate service layer.
Well, the model decorated with data annotation attributes does not have to be in the web project next to the controller, it can be in the service layer next to the service, which means all validation logic is in one place.

Related

FluentValidation usage in AspNetMvc n-tier project

I have a multi-layered project. Layers are as follows :
Business
DataAccess
Entities
Core
MvcWebUI
I have a Category class in entity layer:
public class Category : IEntity
{
public int Id { get; set; }
public string Name { get; set; }
}
I also have a CategoryValidator class in the business layer:
public class CategoryValidator : AbstractValidator<Category>
{
public CategoryValidator(IEnumerable<Category> categories)
{
RuleFor(x => x.Name).NotEmpty().MaximumLength(50);
}
}
I have a class in the Core layer for validation.
public class ValidatorTool
{
public static void FluentValidate(IValidator validator, object entity)
{
var result = validator.Validate(entity);
if (result.Errors.Any())
throw new ValidationException(result.Errors);
}
}
I'm performing validation in the Business layer with the FluentValidate method.
But I got stuck when it came to the MvcWebUI layer. According to the FluentValidation documentation, I need to apply an attribute to the entity class as follows:
[Validator(typeof(PersonValidator))]
But since the business layer references the entity layer, I can't reach the CategoryValidator class in the entity layer. (circle reference)
How can I solve this problem?
Did I create the layers incorrectly?
Or should I define the entities as a model again in the Web layer?
Please help me.
Firstly, you probably shouldn't be exposing your entities directly in the UI so I'm going to recommend you create new models there and write validators specifically for them.
Assuming this is wired up correctly, this approach means the validators are automatically fired during the HTTP POST in the MVC app and the model state is automatically updated with a list of errors.
I use this approach extensively, albeit in MVC apps that call an internal API.
In the majority of my cases, the MVC client validates the model and if it passes the checks it then calls the API or service layer after with a DTO / service / entity model which is mapped with Automapper.
The MVC validation is typically light and checks for required fields, lengths, etc.
The API does validation again but it does it on the entity and it goes much deeper this time as it checks for duplicates, invalid entity state, etc. .
One last comment that I would like to add. I wouldn't throw exceptions on validation errors. The UI should use ModelState and the service layer returns a result which the client knows how to merge back into ModelState so either scenario results in the users getting a nice list of errors to deal with.
Hope this helps!
Generally you have 2 ways to perform validation:
Validate View Models (used in most cases)
Internal Business Entities validation (which most often used with 1-st)
For 1-st point you validate view models (on client and server), which placed in your Web project. In that case you should place view model validators in Web project too. [Validator(typeof(PersonValidator))] attribute is needed for linking view model parameter of action and action itself to perform validation before action execution. As in documentation:
Internally, FluentValidation’s MVC integration makes use of a validator factory to know how to work out which validator should be used to validate a particular type. By default, FluentValidation ships with an AttributedValidatorFactory that allows you to link a validator to the type that it validates by decorating the class to validate with an attribute that identifies its corresponding validator.
If you want to validate business models (2-nd point), not/not only view models, you need to place entity validators to Business project and register them in your IoC container (example with Castle Windsor), and change validator tool next way:
public class ValidatorTool
{
public static void FluentValidate<T>(IContainer container, T entity) // replace IContainer with your actual container interface name
{
var validator = container.Resolve<IValidator<T>>();
var result = validator.Validate(entity);
if (result.Errors.Any())
throw new ValidationException(result.Errors);
}
}

in a well-constructured cms-type system where in the architecture should a business object be created?

This is a question regarding architecture.
Let's say that I have created a layered system in ASP.NET MVC with a good domain layer which uses the repository pattern for data-access. One of those domain objects is Product. At the CMS-side I have a view for creating and editing products. And I have a front-end where that product should be shown. And these views differ considerably so that a different viewmodel for them is appropriate.
1) Where should a new Product object be created when the user enters data for a new product in the data entrance view? In the controller? But making the controller responsible for object creation could hurt the Single Responsibility principle. Or should the factory pattern be used? That would mean that the factory would be very specific, because the data entered would be passed 'as is' to the factory. So coding against an IProductFactory would not be possible, because the input data is specific to that data entrance view. So is it right that we have a tight coupling between this controller and the factory?
2) The Product viewmodel to be shown at the frontend, where should that come from? The answer seems to me a ViewModelFactory that takes the domain object Product and creates a view from it. But again, this viewmodelfactory would be specific for this view, because the viewmodel we are asking for is specific. So is it right then that the controller and the viewmodelfactory would be tightly coupled?
3) Validation: The input data should be validated at the frontend, but the domain layer should also validate the product (because the domain layer knows nothing about the UI and does not even know IF the UI does validation and thus should not depend upon validation there). but where should the validation go? The ProductFactory seems to be a good choice; it seems to me that that adheres to SRP, if the task of a product factory is described as 'creating valid product objects.'
But perhaps the Product business object should contain the validation. That seems more appropriate because validation of a product will not only be needed at creation time but at other places as well. But how can we validate a Product that is not yet created? Should the Product business object then have methods like IsNameValid, IsPriceValid etc??
I'm going to answer your second question first.
Yes, viewmodels should be tightly coupled with the controller. You shouldn't need a ViewModelFactory though. Something like AutoMapper or ValueInjecter should be good enough for converting domain Product to ProductViewModel.
As for your first question, you should keep your domain Product Factory separate from your controller. There are a few different approaches you could use. One would be creating a factory method that only takes scalar values as method arguments -- for example string, bool, etc, other primitives, and pure .NET types.
You can then have your controller pass the scalars to the factory method from the viewmodel. This is loosely coupled, and highly cohesive.
For example:
[HttpPost]
public ActionResult CreateProduct(ProductViewModel model)
{
if (ModelState.IsValid)
{
// assuming product factory is constructor-injected
var domainProduct = _productFactory.BuildProduct(
model.Name, model.Price, model.Description);
// ... eventually return a result
}
return View(model);
}
Another approach is to put the methods for passing viewmodel properties directly on the domain object, but for this approach, it is best to make your property setters non-public:
[HttpPost]
public ActionResult CreateProduct(ProductViewModel model)
{
if (ModelState.IsValid)
{
// assuming no product factory
var domainProduct = new Domain.Product();
domainProduct.SetName(model.Name);
domainProduct.SetPrice(model.Price);
domainProduct.SetDescription(model.Description);
// ... eventually return a result
}
return View(model);
}
I prefer the first option because it's less verbose, and keeps object creation in your domain layer. However both are loosely coupled, because you are not sharing viewmodel types between your MVC layer and your domain layer. Instead your higher layer (MVC) is taking a dependency in the domain layer, but your domain layer is free from all MVC concerns.
Response to first 2 comments
Second comment first, re validation: It doesn't necessarily have to be the product factory's responsibility to enforce validation, but if you want to enforce business rules in the domain, validation should happen at the factory or lower. For example, a product factory could instantiate a product and then delegate build operations to methods on the entity -- similar to the SetXyzProperty methods above (difference being those methods might be internal to the domain lib instead of public). In this case, it would be the product entity's responsibility to enforce validation on itself.
If you throw exceptions to enforce validation, those would bubble up through the factory and into the controller. This is what I generally try to do. If a business rule ever ends up bubbling to the controller, then it means MVC is missing a validation rule and ModelState.IsValid should be false. Also, this way you don't have to worry about passing messages back from the factory -- business rule violations will come in the form of an exception.
As for your first comment, yes: MVC takes a dependency on the domain, not vice versa. If you wanted to pass a viewmodel to the factory, your domain would be taking a dependency on whatever lib the viewmodel class is in (which should be MVC). It's true that you could end up with a lot of factory method args, or factory method overload explosion. If you find this happening, it might be better to expose more granular methods on the entity itself than relying on the factory.
For example, you might have a form where the user can quickly click to change just the name or price of a Product, without going through the whole form. That action could even happen over ajax using JSON instead of a full browser POST. When the controller handles it, it might be easier to just invoke myProduct.SetPriceOrName(object priceOrName) instead of productFactory.RePriceOrRename(int productId, object priceOrName).
Response to question update
Others may have different opinions, but in mine, the business domain should not expose a validation API. That's not to say you can't have an IsValidPrice method on the entity. However, I don't think it should be exposed as part of the public API. Consider the following:
namespace NinetyNineCentStore.Domain
{
public class Product
{
public decimal Price { get; protected set; }
public void SetPrice(decimal price)
{
ValidatePrice(price);
Price = price;
}
internal static bool IsPriceValid(decimal price)
{
return IsPriceAtLeast99Cents(price)
&& IsPriceAtMostNineteen99(price)
&& DoesPriceEndIn99Cents(price);
}
private static bool IsPriceAtLeast99Cents(decimal price)
{
return (price >= 0.99m);
}
private static bool IsPriceAtMostNineteen99(decimal price)
{
return (price <= 19.99m);
}
private static bool DoesPriceEndIn99Cents(decimal price)
{
return (price % 1 == 99);
}
private static void ValidatePrice(decimal price)
{
if (!IsPriceAtLeast99Cents(price))
throw new InvalidOperationException(
"Product price must be at least 99 cents.");
if (!IsPriceAtMostNineteen99(price))
throw new InvalidOperationException(
"Product price must be no greater than 19.99.");
if (!DoesPriceEndIn99Cents(price))
throw new InvalidOperationException(
"Product price must end with 99 cents.");
}
}
}
The above encapsulates validation on the entity, without exposing it in the API. Your factory can still invoke the internal IsPriceValid, but doesn't need to be concerned with every little business rule permutation. When any client, internal or public, tries to violate the rule, an exception is thrown.
This pattern might seem like overkill, but consider business rules that involve more than one property on an entity. For example, say you can break the DoesPriceEndIn99Cents rule when the Product.IsOnSale == true. You already have ValidatePrice encapsulated, so you can accommodate that rule without having to expose a new validation API method.

Recommended approach for model validation that needs to touch the Db

Up to now, most of our validation is performed using validation attributes on our view models.
One additional validation check we need to perform is to validate that a string doesn't already exist in our database.
Originally I was just handling this check within the controller action and then adding an error into ModelState if required. However, I would rather make use of the built-in validation infrastructure.
One method I tried was implementing IValidateableObject on my viewmodel. This feels a bit wrong as I'm calling DependencyResolver:
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var viewModel = validationContext.ObjectInstance as EditPostViewModel;
if (viewModel != null)
{
var slug = (Slug)viewModel.Slug;
var repo = DependencyResolver.Current.GetService<IRepository<Post>>();
var existing = repo.Get(p => p.Slug == slug && p.Id != viewModel.Id);
if (existing != null)
yield return new ValidationResult("Duplicate slug.", new[] { "Slug" });
}
}
Another approach I thought about was using a custom ValidationAttribute. To me this only makes sense if I can re-use it on multiple viewmodels and to re-use it I need to be able to construct a generic repository interface (as per the above code) as I may need IRepository<Foo> or IRepository<Bar> depending on the Model.
Remote Validation is great but I still need to the validation server side.
So what would people recommend or have used themselves to achieve something similar.
Note that I do have unique database constraints on this column but don't want to fall back to exception handling to perform this validation.
Solution
I had a look as the asp.net article #Darin suggested. This approach definitely works, but the article is a bit flawed in that whilst it manages to decouple the validation service away from any direct references to ModelState, you instead end up with a circular dependency where controller depends on the validation service and the validation service depends on ModelState (via a wrapper); which doesn't exist until the controller is created. Nice!
Instead I exposed the IValidationDictionary as a public property on my validation service and set this in my controllers constructor:
slugValidator.ValidationDictionary = new ModelStateWrapper(this.ModelState);
The rest is kind of application specific but essentially I created a validator for each type of "slugable" entity I wanted to validate. These were then injected by my container.
public interface ISlugValidator<TEntity> where TEntity : ISlugable {
IValidationDictionary ValidationDictionary { get; set; }
bool ValidateSlug(Guid? entityId, Guid featureId, Slug slug);
}
I call ValidateSlug(...) just before I check ModelState.IsValid in my controller actions.
This is a good solution for the level of validation I need currently and the fact that most of it can be handled using Data annotations. If my validation/business rules get more complex I will probably switch to FluentValidation (this also works well with Depenency Injection) as it's better suited for externalizing validation logic.
I would recommend doing this type of validation at the service layer and not bother with data annotations.

MVC3 Service Layer Validation. Returning Exception, Custom Object, Model State Dictionary?

Just curious on your thoughts or experiences around service layer validation.
I have to process fairly standard validation such as "object with name property doesn't already exist", but I wasn't sure how to return these validation failures back to the controller.
My initial thought was to implement a standard List<ValidationError> but I've seen it done each and every way so was curious the pros/cons of each.
Thanks for any input.
If you go with System.ComponentModel.DataAnnotations entries you can (as you seem to know) decorate your properties with required and many more tags
public class Person
{
[Required(ErrorMessage="object with name property doesn't already exist")]
public string Name { get; set; }
}
although I personally use ViewModels rather than exposing domain mdoels to the view, your controller action can now do something like:
[HttpPost]
public ActionResult SavePerson(Person model)
{
if (ModelState.IsValid)
{
// your model validates - do things
return RedirectToAction("success view here");
}
return View(model);
}
This is one of the standard 'post' handler patterns in MVC. This is the simplest path to getting your object model validating in my opinion.
From there, there are a few other options - your domain object can implement IValidatedableObject and you can yield return the errors (see http://buildstarted.com/2010/09/20/mvc-3s-ivalidatableobject/ as an example).
I'd recommend not mixing the two though, as if you are using dataannotations and have even a single invalid property, the IsValid method on IValidatableObject will not be called.
From there, there's lots you can do with custom validation attributes (the extended version of IsValid seems to give you more flexibility http://msdn.microsoft.com/en-us/library/gg480674%28v=vs.98%29.aspx)
Hope some of the above helps - once you get past the basics there's a lot you can do with it and things like client validation of custom attributes etc. are all fun.
Cheers,
Terry
[edit to add:
After re-reading your post, it may be that you want to only validate at the service layer? If so, I've used the following approach:
public void Setname(string newName)
{
Validator.ValidateProperty(newName, new ValidationContext(this, null, null) { MemberName = "Name" });
Name = newName;
}
obviously your Name property would need a { get; private set; } for this, though you could always add the Validator.ValidateProperty into an extended setter for the public property either.
]
On a new project I'm working on (first time mvc) I've been using the ms code contracts (which throw exceptions) and do all the validation on my domain objects themselves. For things that can't be validated there (such as validations that require database access) I validate in my services and throw exceptions. Additionally like the poster above I have whole separate view models for everything that have data annotations validators on them. The exceptions bubble up and I catch them in the controller and append to the ModelState. There's a lot of overlap with those and the view model validation but it's not much extra effort and allows me to vary the validation per view and yet still have the "core" validations be required.
The book pro asp mvc 2 has another nice way - write a class that inherits Exception and contains a collection of errors. Then you do your validations, add to the collection then throw the exception then he catches it in the controller and copies over to ModelState. This method will let you catch ALL the errors in one exception instead of just one at the service layer.

How to mock a model in ASP.NET MVC?

I've made a custom model, and I want to mock it. I'm fairly new to MVC, and very new to unit testing. Most approaches I've seen create an interface for the class and then make a mock that implements the same interface. However I can't seem to get this to work when actually passing the interface into the View. Cue "simplified" example:
Model-
public interface IContact
{
void SendEmail(NameValueCollection httpRequestVars);
}
public abstract class Contact : IContact
{
//some shared properties...
public string Name { get; set; }
public void SendEmail(NameValueCollection httpRequestVars = null)
{
//construct email...
}
}
public class Enquiry : Contact
{
//some extra properties...
}
View-
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<project.Models.IContact>" %>
<!-- other html... -->
<td><%= Html.TextBoxFor(model => ((Enquiry)model).Name)%></td>
Controller-
[HttpPost]
public ActionResult Index(IContact enquiry)
{
if (!ModelState.IsValid)
return View(enquiry);
enquiry.SendEmail(Request.ServerVariables);
return View("Sent", enquiry);
}
Unit Testing-
[Test]
public void Index_HttpPostInvalidModel_ReturnsDefaultView()
{
Enquiry enquiry = new Enquiry();
_controller.ModelState.AddModelError("", "dummy value");
ViewResult result = (ViewResult)_controller.Index(enquiry);
Assert.IsNullOrEmpty(result.ViewName);
}
[Test]
public void Index_HttpPostValidModel_CallsSendEmail()
{
MockContact mock = new MockContact();
ViewResult result = (ViewResult)_controller.Index(mock);
Assert.IsTrue(mock.EmailSent);
}
public class MockContact : IContact
{
public bool EmailSent = false;
void SendEmail(NameValueCollection httpRequestVars)
{
EmailSent = true;
}
}
Upon a HttpPost I get a "Cannot create an instance of an interface" exception. I seems that I can't have my cake (passing a model) and eat it (pass mock for unit testing). Maybe there's a better approach to unit testing models bound to views?
thanks,
Med
I'm going to throw it out there, if you need to mock your models you're doing it wrong. Your models should be dumb property bags.
There is absolutely no reason that your model should have a SendEmail method. That is functionality that should be invoked from a controller calling to an EmailService.
Responding to your question:
After years of working with Separation of Concern (SOC) patterns like MVC, MVP, MVVM and seeing articles from people brighter than me (I wish I could find the one I'm thinking off about this but maybe I read it in a magazine). You will eventually conclude in an enterprise application you will end up with 3 distinct sets of model objects.
Previously I was a very big fan of doing Domain Driven Design (DDD) using a single set of business entities that were both plain old c# objects (POCO) and Persistent Ignorant (PI). Having domain models that are POCO/PI leaves you with a clean slate of objects where there is no code related to accessing the object storage or having other attributes that have schematic meaning for only 1 area of the code.
While this works, and can work fairly well for a period of time, there is eventually a tipping point where the complexity of expressing the relationship between View, Domain Model, and Physical Storage Model becomes too complex to express correctly with 1 set of entities.
To solve the impedance mismatches of View, Domain and Storage you really need 3 sets of models. Your ViewModels will exactly match your views binding to facilitate it to be easy to work with the UI. So this will frequently have things such as adding a List to populate drop downs with values that are valid for your edit view/action.
In the middle is the Domain Entities, these are the entities that you should validate against your business rules. So you will map to/from them on both sides to/from the view and to/from the storage layer. In these entities is where you could attach your code to do validation. I personally am not a fan of using attributes and coupling validation logic into your domain entities. It does make alot of sense to couple validation attributes into your ViewModels to take advantage of the built in MVC client side validation functionality.
For validation I would recommend using a library like FluentValidation (or your own custom one, they're not hard to write) that lets you separate your business rules from your objects. Although with new features with MVC3 you can do remote validation severside and have it display client side, this is an option to handle true business validation.
Finally you have your storage models. As I said previously I was very zealous on having PI objects being able to be reused through all layers so depending on how you setup your durable storage you might be able to directly use your domain objects. But if you take advantage of tools like Linq2Sql, EntityFramework (EF) etc you will most likely have auto generated models with code for interacting with the data provider so you will want to map your domain objects to your persistence objects.
So wrap all of this up this would be a standard logic flow in MVC actions
User goes to edit product page
EF queries the database to get the existing product information, inside the repository layer the EF data objects are mapped to the Business Entities (BE) so all the data layer methods return BEs and have no external coupling to the EF data objects. (So if you ever change your data provider you don't have to alter a single line of code except for the internal implementation)
The controller gets the Product BE and maps it to a Product ViewModel (VM) and adds collections for the different options that can be set for drop down lists
Return View(theview, ProductVM)
User edits the product and submits the form
Client side validation is passed (useful for date validation / number validation instead of having to submit the form for feedback)
The ProductVM gets mapped back to ProductBE at this point you would validate the business rules along the lines ValidationFactory.Validate(ProductBE), if it's invalid return messages back to view and cancel edit, otherwise continue
You pass the ProductBE into your repository model, inside the internal implementation of the data layer you map the ProductBE to the Product Data Entity for EF and update the database.
2016 edit: removed usages of Interface as separation of concerns and interfaces are entirely orthogonal.
Your issue is here:
public ActionResult Index(IContact enquiry)
MVC in the background has to create a concrete type to pass to the method when calling it. In this method's case, MVC needs to create a type which implements IContract.
Which type? I dunno. Neither does MVC.
Instead of using interfaces in order to be able to mock your models, use normal classes that have protected methods which you can override in mocks.
public class Contact
{
//some shared properties...
public string Name { get; set; }
public virtual void SendEmail(NameValueCollection httpRequestVars = null)
{
//construct email...
}
}
public class MockContact
{
//some shared properties...
public string Name { get; set; }
public bool EmailSent {get;private set;}
public override void SendEmail(NameValueCollection vars = null)
{
EmailSent = true;
}
}
and
public ActionResult Index(Contact enquiry)
It is possible to use interfaces.
See: http://mvcunity.codeplex.com/

Resources