I am exploring Sharp Architecture and I would like to know how to
access the validation results after calling Entity.IsValid().
I have two scenarios e.g.
1) If the entity.IsValid() return false, I would like to add the
errors to ModelState.AddModelError() collection in my controller.
E.g. in the Northwind sample we have an EmployeesController.Create()
action when we do employee.IsValid(), how can I get access to the
errors?
public ActionResult Create(Employee employee) {
if (ViewData.ModelState.IsValid && employee.IsValid()) {
employeeRepository.SaveOrUpdate(employee);
}
// ....
}
[I already know that when an Action method is called, modelbinder
enforces validation rules(nhibernate validator attributes) as it
parses incoming values and tries to assign them to the model object
and if it can't parse the incoming values then it register those as
errors in modelstate for each model object property. But what if i
have some custom validation. Thats why we do ModelState.IsValid
first.]
2) In my test methods I would like to test the nhibernate validation
rules as well. I can do entity.IsValid() but that only returns true/
false. I would like to Assert against the actual error not just true/
false.
In my previous projects, I normally use a wrapper Service Layer for
Repositories, and instead of calling Repositories method directly from
controller, controllers call service layer methods which in turn call
repository methods. In my Service Layer all my custom validation rules
resides and Service Layer methods throws a custom exception with a
NameValueCollection of errors which I can easily add to ModelState in
my controller. This way I can also easily implement sophisticated
business rules in my service layer as well. I kow sharp architecture
also provides a Service Layer project. But what I am interested in and
my next question is:
How I can use NHibernate Vaidators to implement sophisticated custom
business rules (not just null,empty, range etc.) and make
Entity.IsValid() to verify those rules too ?
"How I can use NHibernate Vaidators to implement sophisticated custom business rules (not just null,empty, range etc.) and make Entity.IsValid() to verify those rules too ?"
You have to create a custom validation attribute:
here is an example:
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class LoginUniqueAttribute : ValidationAttribute
{
private static readonly string DefaultErrorMessage = MUI.LoginNameInUse;
public LoginUniqueAttribute()
: base(DefaultErrorMessage)
{
}
public override string FormatErrorMessage(string name)
{
return DefaultErrorMessage;
}
public override bool IsValid(object value)
{
if (string.IsNullOrEmpty((string)value))
{
return true;
}
var userService = IoC.Resolve<IUserService<User>>();
return userService.GetByLogins(new[] { (string)value }).Count() == 0;
}
}
and usages into a UserInput dto
[Required]
[LoginUniqueAttribute]
[RegularExpression("^[A-Za-z0-9.'\\s]+$", ErrorMessage = "Only characters and digits are allowed")]
[DisplayNameLocalized(typeof(MUI), "LoginName")]
public string LoginName { get; set; }
also do not forget to initialize the validation in your global.asax.cs file on Application_Start:
private void InitializeValidator()
{
var provider = new NHibernateSharedEngineProvider();
NHibernate.Validator.Cfg.Environment.SharedEngineProvider = provider;
}
Related
I have a Validation Framework set up to automatically validate parameters of Web Api action methods (including OData action methods). However, this does not work for PATCH requests that store the changed properties in a Delta<Entity> type.
I've done some digging around and, as you can see in the ASP.NET source code of Delta, it has the NonValidatingParameterBinding attribute, which means that Delta's are not subjected to validation.
Now an obvious solution would be to apply the delta and then perform manual validation of the resulting entity.
But are there other solutions that do not require applying the patch? Ideally it should happen automatically before the action method is called...
Thanks.
It was an explicit design decision to not validate Delta<Entity>. Reason being, a Delta<Entity> is only a partial entity and by definition could be invalid. As you have guessed, the proper approach is to validate the entity after the Delta<TEntity> is applied on top of it.
Sample code,
public void Patch(Delta<Customer> delta)
{
Customer c = new Customer();
delta.Patch(c);
Validate(c, typeof(Customer));
}
private void Validate(object model, Type type)
{
var validator = Configuration.Services.GetBodyModelValidator();
var metadataProvider = Configuration.Services.GetModelMetadataProvider();
HttpActionContext actionContext = new HttpActionContext(ControllerContext, Request.GetActionDescriptor());
if (!validator.Validate(model, type, metadataProvider, actionContext, String.Empty))
{
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState));
}
}
Complete sample here.
We too arrived at this problem. However, we are using a custom version of Delta<T> (heavily based on OData).
The core issue (apart from [NonValidatingParameterBinding]) is that the entity is hidden (behind delta.GetEntity()) and hence will not be validated. Also we only want to validate changed properties.
We solved this by adding the IValidateObject interface to our custom Delta class, making the signature as follows:
[NonValidatingParameterBinding]
public class Delta<TEntityType> : DynamicObject, IDelta, IValidatableObject
where TEntityType : class
This can probably also be done in a class inheriting from OData's Delta<T>, but that is not something we have tried.
Implementation of the interface looks like this:
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var entity = this.GetEntity();
var innerValidationContext = new ValidationContext(entity);
List<ValidationResult> validationResults = new List<ValidationResult>();
foreach (var propertyName in this.GetChangedPropertyNames())
{
innerValidationContext.MemberName = propertyName;
Validator.TryValidateProperty(EntityType.GetProperty(propertyName).GetValue(entity), innerValidationContext, validationResults);
}
return validationResults;
}
Hope this helps!
/Victor
I am looking for a way to return the following information from my custom validation code:
public enum ValidationErrorTypeFlags
{
Error_Input = 1 << 0, // a "field specific" error which is checked both clientside and serverside
Error_Input_ServerSide = 1 << 1, // a "field specific" error which can only be checked serverside
Error_General = 1 << 2 // serverside general error
}
Inside the validation code (either an IValidatableObject or a ValidationAttribute), when I detect an error, I would like to be able to associate one of the above error types with the ValidationResult.
Then I want to be able to iterate through the validation errors in either the Controller or the View and distinguish between these error types.
I'm currently using MVC 3 (happy to upgrade to 4).
NB:
ModelState does not preserve ValidationResults AFAIK - you can only access errors in ViewData.ModelState.Values.Items[x].Errors - and these have been converted to System.Web.Mvc.ModelError
It seems that MVC validation only allows you to access [key, 'error message'] type validation results after validation has completed.
The hack I'm using at present is to decorate the error message inside the custom validation code:
var field = new[] { validationContext.DisplayName };
return new ValidationResult("+Invalid format - use yyyy-mm-dd", field);
And then look for error messages which start with +,-,* in the controller.
From custom validation code (no idea how to accomplish from built-in ones) you can do that by creating a custom ValidationResult class by inheriting from the base and return from your custom validation attributes.
public class CustomValidationResult: ValidationResult
{
// additional properties
}
Then from the controller you can cast and check if the validation result is your custom type and act accordingly.
Update:
The above idea don't work because the ValidationResult class is in DataAnnotations assembly and they are converted into ModelValidationResult and that's all we can access in MVC.
It seems passing extra information from the data annotation validations to the MVC looks like not quite easy!
I was going through the source code and found that it is the ValidatableObjectAdapter that converts the IEnumerable<ValidationResult> into IEnumerable<ModelValidationResult>. I don't see much benefit on extending this class but we can easily create a custom ValidatableObjectAdapter by implementing the ModelValidatorand duplicating the Validate code.
We have to create a custom ModelValidationResult and custom ValidationResult(it is this custom ValidationResult we will b returning from validations) and in the ConvertResults method we can put our conversion code that takes care of the additional information.
public class CustomValidatableObjectAdapter : ModelValidator
{
public CustomValidatableObjectAdapter(ModelMetadata metadata, ControllerContext context)
: base(metadata, context)
{
}
public override IEnumerable<ModelValidationResult> Validate(object container)
{
object model = Metadata.Model;
if (model == null)
{
return Enumerable.Empty<ModelValidationResult>();
}
IValidatableObject validatable = model as IValidatableObject;
if (validatable == null)
{
throw new Exception("model is of not type validatable");
}
ValidationContext validationContext = new ValidationContext(validatable, null, null);
return ConvertResults(validatable.Validate(validationContext));
}
private IEnumerable<ModelValidationResult> ConvertResults(IEnumerable<ValidationResult> results)
{
foreach (ValidationResult result in results)
{
// iterate the ValidationResult enumeration and cast each into CustomValidationResult
// and conver them into enumeration of CustomModelValidationResult.
}
}
}
Finally we have to tell the DataAnnotationsModelValidatorProvider use this our CustomValidatableObjectAdapter in the Application_Start event of Global.asax.cs.
DataAnnotationsModelValidatorProvider.RegisterDefaultValidatableObjectAdapterFactory((metadata, context) => new CustomValidatableObjectAdapter(metadata, context));
So you have to create a custom ValidationResult, custom ModelValidationResult and a custom ValidatableObjectAdapter.
I haven't tested this but I hope this will work. I may suggest a better and easier solution than this.
I am using ASP.NET MVC 2 with nhibernate. I have this Sales class. Sales has many Payments. Sales' payments should not be modified once the sales' status becomes confirmed. I need suggestions on how to enforce this.
I'm stumped on several things when trying to put this validations:
For adding and deleting payments:
I can create AddPayment and DeletePayment methods in Sales, but everybody must remember to use these instead of adding and deleting the payments collection directly
I don't want to hide the payments collection because nhibernate needs it, also this collection is used in other parts of the software
For modifying existing payments:
I don't think I should put the validation in the Payments setters because nhibernate needs to access the setters.
Should I throw exception? There's a discussion about the disadvantages of throwing exception to prevent object entering invalid state. In my case object state after modification may still be valid, but I want to block the modification. Is throwing exception reasonable in this case? What are the alternatives?
Should I enforce this in the controller actions?
You can hide the collection by making it protected or even private. NHibernate will still find it. Alternatively you could have the collection getter return an immutable collection when the sales status is the restricted value.
private ISet<Payment> _payments;
public virtual ISet<Payment> Payments
{
get
{
if (Status == SalesStatus.Confirmed)
return new ImmutableSet<Payment>(_payments);
return _payments;
}
private set { _payments = value; }
}
Putting validation rules in the setters is also fine. You can tell NHibernate to access the backing field directly (you may have to add a backing field if you're currently using auto properties).
<property name="_name" access="field"/>
<property name="Description" access="nosetter.camelcase-underscore"/>
Edit for the additional question...
I don't tend to throw exceptions until right before a save. Throwing them earlier, like in a property setter, can be annoying to UI developers who have to go back to the user with just one error at a time. I do mostly MVC applications too, so I've been using the System.ComponentModel.DataAnnotations validation attributes of late. While limited in some respects, they work well with MVC for the model checks at the browser and in the controller. If you use those, however, I recommend creating a custom interceptor to check them all right before a save. The interceptor is where I will throw an exception if anything is awry.
There are several options:
One is to have a trigger in the database, then you would be 100% sure
Your suggestion of AddPayment and DeletePayment, combined with some code review is probably the best way to go.
I would introduce two new projects (layers) in your solution:
a model layer
a service (or business) layer
Your model layer should consist of interfaces and supporting types:
public interface ISales
{
IEnumerable<IPayment> GetPayments();
}
public enum PaymentStatus
{
Unknown,
Confirmed
}
public interface IPayment
{
// your public properties
PaymentStatus Status { get; set; }
}
You should move your NHibernate classes into the service layer and hide them with internal. Your NHibernate classes implement the model interfaces:
internal class Sales : ISales
{
public IEnumerable<IPayment> GetPayments()
{
// your implementation
}
}
internal class Payment : IPayment
{
// your public properties
public PaymentStatus Status { get; set; }
}
public class SalesService
{
public ISales FindByKey(int key)
{
// your implementation
}
public void AddPayment(ISales sales, IPayment payment)
{
// throw exception if validation fails
}
public void DeletePayment(ISales sales, IPayment payment)
{
// throw exception if validation fails
}
}
public class PaymentService
{
public IPayment FindByKey(int key)
{
// your implementation
}
}
Since the classes Sales and Payment are hidden, your controllers are foced to use the service classes:
public class SalesController : Controller
{
private readonly SalesService salesService;
private readonly PaymentService paymentService;
public SalesController()
{
salesService = new SalesService();
paymentService = new PaymentService();
}
public ActionResult AddPayment(int salesId, int paymentId)
{
var sales = salesService.FindByKey(salesId);
var payment = paymentService.FindByKey(paymentId);
salesService.AddPayment(sales, payment);
return RedirectToAction("Index");
}
}
You should also consider using an IoC container like autofac or Ninject.
Description
My solution has these projects:
DAL = Modified Entity Framework
DTO = Data Transfer objects that are able to validate themselves
BL = Business Layer Services
WEB = presentation Asp.net MVC application
DAL, BL and WEB all reference DTO which is great.
The process usually executes this way:
A web request is made to the WEB
WEB gets DTOs posted
DTOs get automagically validated via custom ActionFilter
validation errors are auto-collected
(Validation is OK) WEB calls into BL providing DTOs
BL calls into DAL by using DTOs (can either pass them through or just use them)
DTO Validation problem then...
My DTOs are able to validate themselves based on their own state (properties' values). But right now I'm presented with a problem when this is not the case. I need them to validate using BL (and consequently DAL).
My real-life example: User registers and WEB gets a User DTO that gets validated. The problematic part is username validation. Its uniqueness should be checked against data store.
How am I supposed to do this?
There's additional info that all DTOs implement an interface (ie. User DTO implements IUser) for IoC purposes and TDD. Both are part of the DTO project.
Impossible tries
I can't reference BL in DTO because I'll get circular reference.
Compilation error
I can't create an additional DTO.Val project that would reference partial DTO classes and implement their validation there (they'd reference BL + DTO).
Partial classes can't span assemblies.
Possible tries
Create a special ActionFilter that would validate object against external conditions. This one would be created within WEB project thus seeing DTO and BL that would be used here.
Put DTOs in BL and keep DTO interfaces as actual DTOs referenced by other projects and refactor all code to use interfaces instead of concrete classes.
Don't handle external dependant validation and let external dependencies throw an exception - probably the worst solution to this issue
What would you suggest?
I would suggest an experiment that i have only been trialling for the last week or so.
Based on this inspiration i am creating DTOs that validate a little differently to that of the DataAnnotations approach. Sample DTO:
public class Contact : DomainBase, IModelObject
{
public int ID { get; set; }
public string Name { get; set; }
public LazyList<ContactDetail> Details { get; set; }
public DateTime Updated { get; set; }
protected override void ConfigureRules()
{
base.AddRule(new ValidationRule()
{
Properties = new string[] { "name" },
Description = "A Name is required but must not exceed 300 characters in length and some special characters are not allowed",
validator = () => this.Name.IsRequired300LenNoSpecial()
});
base.AddRule(new ValidationRule()
{
Properties = new string[] { "updated" },
Description = "required",
validator = () => this.Updated.IsRequired()
});
}
}
This might look more work than DataAnnotations and well, that's coz it is, but it's not huge. I think it's more presentable in the class (i have some really ugly DTO classes now with DataAnnotations attributes - you can't even see the properties any more). And the power of anonymous delegates in this application is almost book-worthy (so i'm discovering).
Base class:
public partial class DomainBase : IDataErrorInfo
{
private IList<ValidationRule> _rules = new List<ValidationRule>();
public DomainBase()
{
// populate the _rules collection
this.ConfigureRules();
}
protected virtual void ConfigureRules()
{
// no rules if not overridden
}
protected void AddRule(ValidationRule rule)
{
this._rules.Add(rule);
}
#region IDataErrorInfo Members
public string Error
{
get { return String.Empty; } // Validation should call the indexer so return "" here
} // ..we dont need to support this property.
public string this[string columnName]
{
get
{
// get all the rules that apply to the property being validated
var rulesThatApply = this._rules
.Where(r => r.Properties.Contains(columnName));
// get a list of error messages from the rules
StringBuilder errorMessages = new StringBuilder();
foreach (ValidationRule rule in rulesThatApply)
if (!rule.validator.Invoke()) // if validator returns false then the rule is broken
if (errorMessages.ToString() == String.Empty)
errorMessages.Append(rule.Description);
else
errorMessages.AppendFormat("\r\n{0}", rule.Description);
return errorMessages.ToString();
}
}
#endregion
}
ValidationRule and my validation functions:
public class ValidationRule
{
public string[] Properties { get; set; }
public string Description { get; set; }
public Func<bool> validator { get; set; }
}
/// <summary>
/// These extention methods return true if the validation condition is met.
/// </summary>
public static class ValidationFunctions
{
#region IsRequired
public static bool IsRequired(this String str)
{
return !str.IsNullOrTrimEmpty();
}
public static bool IsRequired(this int num)
{
return num != 0;
}
public static bool IsRequired(this long num)
{
return num != 0;
}
public static bool IsRequired(this double num)
{
return num != 0;
}
public static bool IsRequired(this Decimal num)
{
return num != 0;
}
public static bool IsRequired(this DateTime date)
{
return date != DateTime.MinValue;
}
#endregion
#region String Lengths
public static bool IsLengthLessThanOrEqual(this String str, int length)
{
return str.Length <= length;
}
public static bool IsRequiredWithLengthLessThanOrEqual(this String str, int length)
{
return !str.IsNullOrTrimEmpty() && (str.Length <= length);
}
public static bool IsRequired300LenNoSpecial(this String str)
{
return !str.IsNullOrTrimEmpty() &&
str.RegexMatch(#"^[- \r\n\\\.!:*,#$%&""?\(\)\w']{1,300}$",
RegexOptions.Multiline) == str;
}
#endregion
}
If my code looks messy well that's because i've only been working on this validation approach for the last few days. I need this idea to meet a few requirements:
I need to support the IDataErrorInfo interface so my MVC layer validates automatically
I need to be able to support complex validation scenarios (the whole point of your question i guess): I want to be able to validate against multiple properties on the same object (ie. StartDate and FinishDate); properties from different/multiple/associated objects like i would have in an object graph; and even other things i haven't thought of yet.
I need to support the idea of an error applying to more than one property
As part of my TDD and DDD journey i want my Domain Objects to describe more my 'domain' than my Service layer methods, so putting these complex conditions in the model objects (not DTOs) seems to achieve this
This approach i think will get me what i want, and maybe you as well.
I'd imagine if you jump on board with me on this that we'd be pretty 'by ourselves' but it might be worth it. I was reading about the new validation capabilities in MVC 2 but it still doesn't meet the above wish list without custom modification.
Hope this helps.
The S#arp Architecture has an [DomainSignature] method identifier that used with the class level validator [HasUniqueDomainSignature] will do the work. See the sample code below:
[HasUniqueDomainSignature]
public class User : Entity
{
public User()
{
}
public User(string login, string email) : this()
{
Login = login;
Email = email;
}
[DomainSignature]
[NotNullNotEmpty]
public virtual string Login { get; set; }
[DomainSignature]
public virtual string Email { get; set; }
}
Take a closer look at http://www.sharparchitecture.net/
I had this exact same problem and after trying to find a work around for days and days and days, I ended up merging my DTO, DAL, and BL into one library. I kept my presentation layer separate.
Not sure if that is an option for you or not. For me, I figured that my chances of ever changing the data store were very slight, and so the separate tier wasn't really needed.
I also have implemented the Microsoft Validation Application Block for all my DTO validations. They have a "Self Validation" method that lets you perform complex validations.
Resulting solution
I ended up using controller action filter that was able to validate object against external factors that can't be obtained from the object itself.
I created the filter that takes the name of the action parameter to check and validator type that will validate that particular parameter. Of course this validator has to implement certain interface to make it all reusable.
[ValidateExternalFactors("user", typeof(UserExternalValidator))]
public ActionResult Create(User user)
validator needs to implement this simple interface
public interface IExternalValidator<T>
{
bool IsValid(T instance);
}
It's a simple and effective solution to a seemingly complex problem.
I am a bit confused about the service layer and using it validation.
So I am looking through this tutorial: http://www.asp.net/learn/mvc/tutorial-38-cs.aspx
First if you look at List 3
using System.Collections.Generic;
using System.Web.Mvc;
namespace MvcApplication1.Models
{
public class ProductService : MvcApplication1.Models.IProductService
{
private ModelStateDictionary _modelState;
private IProductRepository _repository;
public ProductService(ModelStateDictionary modelState, IProductRepository repository)
{
_modelState = modelState;
_repository = repository;
}
protected bool ValidateProduct(Product productToValidate)
{
if (productToValidate.Name.Trim().Length == 0)
_modelState.AddModelError("Name", "Name is required.");
if (productToValidate.Description.Trim().Length == 0)
_modelState.AddModelError("Description", "Description is required.");
if (productToValidate.UnitsInStock < 0)
_modelState.AddModelError("UnitsInStock", "Units in stock cannot be less than zero.");
return _modelState.IsValid;
}
public IEnumerable<Product> ListProducts()
{
return _repository.ListProducts();
}
public bool CreateProduct(Product productToCreate)
{
// Validation logic
if (!ValidateProduct(productToCreate))
return false;
// Database logic
try
{
_repository.CreateProduct(productToCreate);
}
catch
{
return false;
}
return true;
}
}
public interface IProductService
{
bool CreateProduct(Product productToCreate);
IEnumerable<Product> ListProducts();
}
}
They same interface just with a different name basically why not just use one?
public interface IProductRepository
{
bool CreateProduct(Product productToCreate);
IEnumerable<Product> ListProducts();
}
public interface IProductService
{
bool CreateProduct(Product productToCreate);
IEnumerable<Product> ListProducts();
}
In my book though(the author who I think wrote this tutorial) has changed it to have IProductRepository to void. So that confuses me even more.
So can someone explain why I need 2 interfaces that seems to do the same thing?
My next questions is my repository has a delete function. Do I put this one in my Service layer too(I guess mandatory if you use one Interface but if you use 2 like about then it could be optinal).
So what would I have in my service layer? Would it just call delete function in the repository? Should it just be a void method or should it return bool? I don't think for this method any validation would need to be done?
So I am not sure if a bool would be needed.
From the tutorial you are reading:
So, application flow control logic
belongs in a controller and data
access logic belongs in a repository.
In that case, where do you put your
validation logic? One option is to
place your validation logic in a
service layer.
A service layer is an additional layer
in an ASP.NET MVC application that
mediates communication between a
controller and repository layer. The
service layer contains business logic.
In particular, it contains validation
logic.
EDIT:
I'm not sure if I can explain it to you in a clear way('cause I'm not fluent in English), but I will try:
A service layer is an additional layer in an ASP.NET MVC application that mediates communication between a controller and repository layer, in that you can handle both validation and application businness. Sometimes you service will need to work with two or more methods of its correspondent repository layer so it doesnt need to have the same interface.
A basic example, let's think you have a register form.
you will have the following interfaces
public interface IUserService
{
bool Register(User mUser);
bool Validate(User mUser);
}
public interface IUserRepository
{
User FindUserByEmail(string Email);
bool Insert(User mUser);
}
so you will end up with two class that will do something like:
public class UserRepository: IUserRepository{
User FindUserByEmail(string Email)
{
//do a ninja search and return an user or null
}
bool Insert(User mUser);
{
//Insert user into db
}
}
public class UserService: IUserService
{
public bool Validate(User mUser)
{
//validate user
}
IUserRepository _respository = new UserRepository();
bool Register(User mUser)
{
if(Validate(mUser);
var hasUser = _respository.FindUserByEmail(User.Email);
if(hasUser==null)
return _respository.Insert(mUser);
return false;
}
}
I think you've made an argument for a single interface in this limited case, but the service and repositories perform two very different functions and you may run into issues down the road if they shared a single interface.
What if the CreateProduct() or ListProducts() needed to have different method signatures in either the service or repository?
What if ValidateProduct() should be defined in the interface? The repository certainly shouldn't have to implement that.
As you've pointed out, there's no need for two interfaces that define the same thing in this particular example, but I assume the author's assumption is that down the road they would be different and therefore necessary.