I have been evaluating xVal as framework for validating Entities in the ASP.Net MVC Framework. I have recently discovered that each time a validation rule is broken, xVal cause an excpetion to be thrown. To me is seems incorrect. For example, when a user fills in a form, and forgets to fill three required fields , three exceptions will be thrown. Is this good practice? ( Edit: I also read this, so I guess its not good practice)
What are your experiences of using xVal? Is there good alternative validation framework that does not throw exceptions?
Thanks
(PS: I notice that lots of people are reading this, just to let you know I am using Fluent Validation now)
Have you looked at validation in Beta 2?
http://blogs.msdn.com/rickandy/archive/2009/10/03/client-side-validation-for-mvc-2-p2.aspx
No it's not a good practice to show exceptions instead of some simple messages because nothing seriously has been going wrong... You should instead populate ModelState with these errors and display them on the form using
Html.ValidationMessage("EntityPropertyName");
xVal supports all these. As well as validating on the client side before the form gets posted back.
Some code
When you set DataAnnotations attributes to your entity classes (or their Metadata companion classes) you will most likely also implement Validate() method. the best way would be to use T4 that will auto generate those for you, so you don't have to repeate the same code over and over...
public IEnumerable<ErrorInfo> Validate()
{
IList<ErrorInfo> errors = DataAnnotationsValidationRunner.GetErrors(this).ToList<ErrorInfo>();
return errors.AsEnumerable();
}
All you have to do then is to call this:
IEnumerable<ErrorInfo> errors = entityObjectInstance.Validate();
if (errors.Any())
{
new RulesException(errors).AddModelStateErrors(filterContext.Controller.ViewData.ModelState, entityPropertyName);
}
And to automate this even further, you can implement this in an action filter, so validation will be automatic for your entity objects that get passed into controller action. Controller actions would only need to check whether ModelState.IsValid() then.
One more class you'll need here is (and is taken from the web somewhere):
public static class DataAnnotationsValidationRunner
{
public static IEnumerable<ErrorInfo> GetErrors(object instance)
{
var metadataAttribute = instance.GetType().GetCustomAttributes(typeof(MetadataTypeAttribute), true).OfType<MetadataTypeAttribute>().FirstOrDefault();
var metaClass = metadataAttribute != null ? metadataAttribute.MetadataClassType : instance.GetType();
var metaClassProperties = TypeDescriptor.GetProperties(metaClass).Cast<PropertyDescriptor>();
var modelClassProperties = TypeDescriptor.GetProperties(instance.GetType()).Cast<PropertyDescriptor>();
return from metaProp in metaClassProperties
join modelProp in modelClassProperties on metaProp.Name equals modelProp.Name
from attribute in metaProp.Attributes.OfType<ValidationAttribute>()
where !attribute.IsValid(modelProp.GetValue(instance))
select new ErrorInfo(metaProp.Name, attribute.FormatErrorMessage(string.Empty), instance);
}
}
MVC 2
Validation in Asp.net MVC 2 Beta 2 is similar to what xVal does. So if you're not too far into the project and you can consider using code in development progress as your foundation, maybe that is the way to go for you.
I think xVal is great, I've been using it with Castle Validators and it works perfectly. Just catch the RulesException whenever you're running validation and add the errors to your ModelState, e.g.
try
{
// execute validation runner
}
catch (RulesException ex)
{
ex.AddModelStateErrors(ModelState, "prefix");
}
ASP.NET MVC v2 will introduce its own validation framework.
Related
I'm using VAB to validate some classes with attributes and I'm using a metadata class to share the same validation among different classes.
When i try to validate an object in the controller (btw i'm using asp.net mvc) the ValidationResults does not have errors and my entity should not be valid.
But, ASP.NET MVC does his magic because ModelState.IsValid is false. I guess the problem is the way I'm doing the manual validations.
In Global.asax I'm loading the associations between the classes and metadata classes.
Global.ASAX
private static void RegisterMetadataExtensions()
{
AssociatedMetadataTypeTypeDescriptionProvider typeDescriptionProvider;
typeDescriptionProvider =
new AssociatedMetadataTypeTypeDescriptionProvider(
typeof(FooViewModel), typeof(FooMetadata));
TypeDescriptor.AddProviderTransparent(typeDescriptionProvider,
typeof(FooViewModel));
typeDescriptionProvider =
new AssociatedMetadataTypeTypeDescriptionProvider(
typeof(FooCommand), typeof(FooMetadata));
TypeDescriptor.AddProviderTransparent(
typeDescriptionProvider, typeof(FooCommand));
}
Controller
[HttpPost]
public ActionResult Action(FooViewModel vm)
{
Validator<FooViewModel> validator =
ValidationFactory.CreateValidator<FooViewModel>();
ValidationResults res = validator.Validate(vm);
//res.Count is 0
OR
ValidationResults res = Validation.Validate<FooViewModel>(vm);
//res.Count is 0
//ModelState.IsValid is false
if(ModelState.IsValid)
Any idea is welcome.
Thanks in advanced.
I'm a big fan of the enterprise library, but I think a better way to do validation with MVC is to make your ViewModel implement IValidatableObject. That way, it automatically gets validated during the binding phase that sets ModelState.Isvalid
For your VAB validator to hook into ASP.NET MVC's validation I think you would need to implement ModelValidatorProvider and wrap the VAB validation results as described here ... http://bradwilson.typepad.com/blog/2009/10/enterprise-library-validation-example-for-aspnet-mvc-2.html
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 do I disable Model validation for a single Action in a Controller ?
Or can I do it per model by registering the model type at startup somewhere ?
I want the ModelBinder to bind to the model, but afterwards it should not perform the model validation.
The reason why i dont want validation to happen is because i am trying to move the logic from the controllers to a service layer which will be responsible for validating the models as i cant assume that models being passed to a service contains valid data.
As I understand this is the recommend approach (to not have logic in the controllers), so I find it a bit strange that i cant seem to find anything about how the model validation can be disabled (per action or per model type).
Please notice that I dont want to disable model validation for the entire webapplication (by removing the validation providers), and i dont want to disable the input validation that checks for malicious code being posted.
UPDATE
I am using .Net 4.0 and MVC 3 Preview 1
Just remove the items you don´t need before checking if the model is valid
ModelState.Remove("Email");
if (ModelState.IsValid)
{
// your logic
}
I've solved this problem with this code:
public ActionResult Totals(MyModel model)
{
ModelState.Clear();
return View(model);
}
Not sure it's the right way though.
Unfortunately there seems to be no easy way to disable the model validation happening in the ModelBinder except for registering every single model type you don’t want to validate (including nested complex types) with a specific ModelBinder. It can be done with the following code:
ModelBinders.Binders[typeof(MyModelType)] = new NonValidatingModelBinder();
Creating a SkipValidationAttribute that can be attached to action methods or action method parameters doesn’t seem possible as it should be implemented in the ControllerActionInvoker, but there is no way of letting the ModelBinder know that it should do any validation in the SetProperty() and OnModelUpdated methods when calling BindModel() in the GetParameterValue() method.
I definitely dislike this addition in the 2.0 version, because, as you stated in your question, validation makes more sense in the Service layer. In this way you can reuse it in other non-web applications, and test it more easily without having to mock the auto-validation mechanism.
Validation in Controller layer is pointless because in this part you can only verify model data and not business rules. For example, think of a service responsible of adding new comments and a user that wants to post a new one, the data in the comment he/she is posting may be valid, but what happens if the user is banned to comment because of misbehavior in the past? You should do some validation in the Service layer to ensure this is not happening, and if it does, throwing an exception. In short, validation must be done in the Service layer.
I use xVal as my Validation framework because it's compatible with the DataAnnotationModel, allows me to place validation wherever I want and performs client-side validation without extra-effort, even remote-client side. This is how I use it at the beginning of each of my services, for example, a login service:
public void SignIn(Login login) {
var loginErrors = DataAnnotationsValidationRunner.GetErrors(login);
// Model validation: Empty fields?
if (loginErrors.Any())
throw new RulesException(loginErrors);
// Business validation: Does the user exist? Is the password correct?
var user = this._userRepository.GetUserByEmail(login.Email);
if (user == null || user.Password != login.Password)
throw new RulesException(null, "Username or password invalids");
// Other login stuff...
}
Simple, web-independent and easy... then, in the Controller:
public RedirectResult Login(Login login) {
// Login the user
try {
this._authenticationRepository.SignIn(login);
} catch (RulesException e) {
e.AddModelStateErrors(base.ModelState, "Login");
}
// Redirect
if (base.ModelState.IsValid)
return base.Redirect(base.Url.Action("Home"));
else return base.Redirect(base.Url.Action("Login"));
}
I would recommend you perform validation in both places rather than trying to turn off validation in the UI. I understand your point that the service cannot assume that it's being passed valid data - that is a valid concern and is the reason your service should have validation. But you should also have validation in your UI. This is also nice because you can have client-side validation to prevent user errors and give you users a better experience.
I know that this already been answered but what you really needed was to extend the DataAnnotationsValidatorProvider and override the GetValidators method.
Then, on startup, you would remove the DataAnnotationsValidatorProvider from ModelValidatorProviders.Providers and add your new one.
Needless to say, if you simply don't want any validation at all, you can simply have the GetValidators method returning an empty collection.
In my case, I need to remove validation only when submitting the forms while still keeping the client-side validation, hence the following:
public class DynamicModelValidatorProvider : DataAnnotationsModelValidatorProvider
{
GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
{
if (context.HttpContext.Request.HttpMethod == "POST")
{
return new ModelValidator[] { };
}
return base.GetValidators(metadata, context, attributes);
}
}
I use
[ ValidateInput( false )]
Not sure if this prevents model validation, or only IIS submit validation.
I'm using the Data Annotation validation extensively in ASP.NET MVC 2. This new feature has been a huge time saver, as I'm now able to define both client-side validation and server-side validation in one place. However, while I was doing some detailed testing, I realized that it's quite easy for someone to bypass the server-side validation if I relied on Data Annotation validation alone. For example, if I defined a required field by annotating the property with the [Required] attribute and placed a textbox for that required field in a form, a user could simply remove the textbox from the DOM (which can easily be done through Firebug) and now the Data Annotation validation will not be triggered on that property during ModelBinding inside of a Controller. To ensure that the "required" validation is triggered, I can repeat the validation after ModelBinding happens, but then I'd be repeating my validation logic.
What is everyone's recommendation on validation? Is Data Annotation validation enough? Or does the validation need to be repeated to ensure that validations get triggered in all situations?
Follow-up comment:
Based on the answers below, it seems that I can't rely on the Model Binder and Data Annotation validation alone. Since we're concluding that additional server-side validation is required, is there an easy way for my Service layer to trigger validation based on what's been defined in the Data Annotations? It seems that this will get us the best of both words...we won't need to repeat the validation code, but we'll still ensure that the validation gets executed even if Model Binder doesn't trigger it.
I'm going to post this follow-up comment as a separate question, as it poses a different question than the original one.
I think to be vigilant concerning security you should choose to you make server validation the priority and ensure that this is always your fallback. Your server validation should work without the client validation. Client validation is more for UX and tho that is paramount to your design, it is secondary to security. With this in mind you will find yourself repeating your validation. A goal is often trying to design your app so that the server and client validation can be integrated as much as possible to reduce the work required to validate on the server and the client. But be assured you must do both.
If bypassing the client validation (by means of DOM manipulation) is avoiding the server validation (which it seems you are indicating) then your server validation for this instance may not be employed appropriately. You should be invoking your server validation again in your controller action or in a service layer. The scenario you describe should not be defeating your server validation.
With the scenario you describe, the DataAnnotation attributes method should be sufficient. It seems that you simply need to make a few code changes to ensure that your server validation is invoked also when submitting the form.
I paired xVal with DataAnnotations and have written my own Action filter that checks any Entity type parameters for validation purposes. So if some field is missing in the postback, this validator will fill ModelState dictionary hence having model invalid.
Prerequisites:
my entity/model objects all implement IObjectValidator interface which declares Validate() method.
my attribute class is called ValidateBusinessObjectAttribute
xVal validation library
Action filter code:
public void OnActionExecuting(ActionExecutingContext filterContext)
{
IEnumerable<KeyValuePair<string, object>> parameters = filterContext.ActionParameters.Where<KeyValuePair<string, object>>(p => p.Value.GetType().Equals(this.ObjectType ?? p.Value.GetType()) && p.Value is IObjectValidator);
foreach (KeyValuePair<string, object> param in parameters)
{
object value;
if ((value = param.Value) != null)
{
IEnumerable<ErrorInfo> errors = ((IObjectValidator)value).Validate();
if (errors.Any())
{
new RulesException(errors).AddModelStateErrors(filterContext.Controller.ViewData.ModelState, param.Key);
}
}
}
}
My controller action is defined like this then:
[ValidateBusinessObject]
public ActionResult Register(User user, Company company, RegistrationData registrationData)
{
if (!this.ModelState.IsValid)
{
return View();
}
...
}
The DataAnnotation is certainly not enough. I use it extensively also to pre-validate my calls to the domain model to get better error reporting and fail as early as possible.
You can however tweak the DataAnnotation Model yourself to ensure properties with [Required] MUST be posted. (will follow up with code later today).
UPDATE
Get the source for DataAnnotations Model Binder and find this line in DataAnnotationsModelBinder.cs
// Only bind properties that are part of the request
if (bindingContext.ValueProvider.DoesAnyKeyHavePrefix(fullPropertyKey)) {
Change it to
// Only bind properties that are part of the request
bool contextHasKey = bindingContext.ValueProvider.DoesAnyKeyHavePrefix(fullPropertyKey);
bool isRequired = GetValidationAttributes(propertyDescriptor).OfType<RequiredAttribute>().Count() > 0;
if (contextHasKey || (!contextHasKey && isRequired)) {
I wrote my own ValidationService for MVC 1.0 by copying patterns from both xVal's DataAnnotationsRuleProvider and Microsoft's DataAnnotationsModelBinder (and Martijn's comments). The service interface is below:
public interface IValidationService
{
void Validate(object instance);
IEnumerable<ErrorInfo> GetErrors(object instance);
}
public abstract class BaseValidationService : IValidationService
{
public void Validate(object instance)
{
var errors = GetErrors(instance);
if (errors.Any())
throw new RulesException(errors);
}
public abstract IEnumerable<ErrorInfo> GetErrors(object instance);
}
The service is a validation runner that walks the property tree of the object instance it receives and actually executes the validation attributes that it finds on each property, building a list of ErrorInfo objects when attributes are not valid. (I'd post the whole source but it was written for a client and I don't know yet if I'm authorized to do so.)
You can then have your controllers, business logic services explicitly invoke validation when you are ready, rather than relying exclusively on the model binder for validation.
There are a couple of other pitfalls that you should be aware of:
The default DataTypeAttribute in data
annotations doesn't actually do any
data type validation, so you'll need
to write a new attribute that
actually uses xVal regular
expressions (or something else) to
perform server-side data type
validation.
xVal doesn't walk
properties to create client-side
validation, so you may want to make
some changes there to get more robust
client-side validation.
If I am allowed and have time, I will try to make more source available...
See codeProject Server-side Input Validation using Data Annotations
Input validation can be done automatically on the client side in
ASP.NET MVC or explicitly validating the model against the rules. This
tip will describe how it can be done manually on the server-side of an
ASP.NET applications or within the repository code of WPF
applications.
// Use the ValidationContext to validate the Product model against the product data annotations
// before saving it to the database
var validationContext = new ValidationContext(productViewModel, serviceProvider: null, items:null);
var validationResults = new List<ValidationResult>();
var isValid = Validator.TryValidateObject(productViewModel, validationContext,validationResults, true);
I have a website where I allow users to create new Part records. I'm trying to figure out the best way to validate specific fields for uniqueness. I want to make sure that somebody doesn't try to add a Part with PartNumber 1234 if that PartNumber already exists on a different Part.
The Web Application is using Asp.net MVC with fluent nHibernate for mapping my objects to the database. I'm using Castle validation on my view models for things like ValidateNonEmpty, ValidateRange, etc. Should I use the ValidateSelf method to query the repository to see if that part number already exists? Something doesn't feel right about using my Repository on the ViewModel.
Would it be better for me to place that logic on the controller action? That doesn't seem right because I expect my ViewModel to already be Validated at the point (during ModelBind).
Or maybe its none of the above. Thanks for any help on this one.
UPDATE
Ok, not sure if this will help, but here is what my Save action looks like for a typical Create Action in my project:
public ActionResult Create(PartViewModel viewModel)
{
//I think I'd like to know if its Valid by this point, not on _repository.Save
if(ModelState.IsValid)
{
try
{
var part = _partCreateViewModelMap.MapToEntity(viewModel);
_repository.Save(part);
return Redirect("~/Part/Details/" + part.Id);
}
catch (Exception e)
{
// skip on down...
}
}
// return view to edit
return View(viewModel);
}
I have been asked this question many times. My friends were worried about whether they can perform data access from the validator code. The answer is simple. If you need to do this, you should do it. Usually we need to do such checks at each level of abstraction. And after all checks you should be ready to catch an exception, caused by unique constraint violation.
If you define a unique constraint within the database, then why not delegate the responsibility to check for whether a unique value already exists to the database? Using NHibernate, you can use the NHibernate.Exceptions.ISQLExceptionConverter interface to capture and transform known errors relating to constraint violations. You can also use NHibernate.Exceptions.IViolatedConstraintNameExtracter implementers (see NHibernate.Exceptions.TemplatedViolatedConstraintNameExtracter) to get at the grubby details of your database exception, and transform it into a user-friendly message, repackage as a validation exception of your chosing and catch it in the relevant controller.
Example of a quick, very specific quick and dirty exception converter from one of my projects:
Imports NHibernate
Imports NHibernate.Exceptions
Imports System.Data.SqlClient
Imports System.Data.Common
Namespace NHibernate
Public Class ConstraintViolationExceptionConverter
Implements ISQLExceptionConverter
Public Function Convert(ByVal adoExceptionContextInfo As Global.NHibernate.Exceptions.AdoExceptionContextInfo) As System.Exception Implements Global.NHibernate.Exceptions.ISQLExceptionConverter.Convert
Dim dbEx As DbException = ADOExceptionHelper.ExtractDbException(adoExceptionContextInfo.SqlException)
If TypeOf dbEx Is SqlException Then
Dim sqlError As SqlException = DirectCast(dbEx, SqlException)
Select Case sqlError.Number
Case 547
Return New ConstraintViolationException(adoExceptionContextInfo.Message, adoExceptionContextInfo.SqlException)
End Select
End If
Return SQLStateConverter.HandledNonSpecificException(adoExceptionContextInfo.SqlException, adoExceptionContextInfo.Message, adoExceptionContextInfo.Sql)
End Function
End Class
End Namespace
Configured through the web.config/nhibernate-configuration/session-factory property element:
<property name="sql_exception_converter">csl.NHibernate.ConstraintViolationExceptionConverter, csl</property>
Edit: Should probably mention that the converter interface has changed in recent versions of NHibernate, the interface from this example is from NHibernate.dll v2.1.0.4000
I typically put a Service layer between my controllers and repositories.
The service layer would then handle the validation and calls to the repository.
Then, if there's a validation error in the service layer, I throw a custom exception, catch it in the controller, and inject the errors in to the model state.
I have no answer for your question but you can check sharparchitecture.net site. It contains some best practives for asp.net mvc and nhibernate. Also I can recommend you to check xval project and tutorials about Validating with Data Annotation Validators
I have found the solution that works for me is to
1.) Ask if the entity is valid to execute your validation work.
2.) After this is complete you should have something on your object to show it's valid or not (in my case I use a CSLA like concept of "broken rules").
3.) If you have something like this you can verify the object is valid before NHibernate tries to persist it as shown below.
The only issue with this approach is that you do need to implement an interface on each entity requiring validation. If you can live with this it will stop NHibernate from persisting the changes of an object that's not valid according to your rules.
using System;
using NHibernate;
using NHibernate.Event;
using Validation.Entities.Interfaces;
using Persistence.SessionBuilder;
namespace Persistence.Validation
{
public class ValidationEventListener : IPreInsertEventListener, IPreUpdateEventListener
{
public bool OnPreInsert(NHibernate.Event.PreInsertEvent #event)
{
var entityToInsert = #event.Entity as IBusinessBase;
if (entityToInsert != null)
{
if (entityToInsert.BrokenRules != null)
{
RollbackTransactionBecauseTheEntityHasBrokenRules();
}
}
return false;
}
public bool OnPreUpdate(NHibernate.Event.PreUpdateEvent #event)
{
var entityToUpdate = #event.Entity as IBusinessBase;
if (entityToUpdate != null)
{
if (entityToUpdate.BrokenRules != null)
{
RollbackTransactionBecauseTheEntityHasBrokenRules();
}
}
return false;
}
private void RollbackTransactionBecauseTheEntityHasBrokenRules()
{
try
{
ISession session = SessionBuilderFactory.GetBuilder().CurrentSession;
if (session != null)
{
session.Transaction.Rollback();
}
}
catch (Exception ex)
{
//this will force a rollback if we don't have a session bound to the current context
throw new NotImplementedException();
}
}
}
}
I would say this matters on your architecture. With MVC apps that I have done in the past we abstract away the domain stuff away from the web stuff and naturally we use dependency injection to avoid hard dependencies.
When it comes to validating the model when you are in the act of binding it, yes you could easily use the service, repository, or whatever you have next in your architecture in a ValidateSelf method. I think the question rises of what about that dependency.
If I remember correctly you can create your own custom binder that will use your dependency injection framework to plug-in any services your model needs for validation when you create it, call MVC's default binder to fill in the object, then call into Castle Validation's framework to do the validation. This isn't a fully thought solution, but hopefully it provokes some ideas.