This project is read-only.

Validation Application Block

Jan 13, 2009 at 7:46 PM
Hi Steve,

I thought I would try to add a provider for the Validation Application Block for kicks, but unless I am missing something, I don't think it can be done due to the fact that the Validator Attributes don't allow access to their values.

For example, if I try to convert the StringLengthValidatorAttribute to a StringLengthRule, I cannot pass in minLength or maxLength to the rule because I cannot gain access to the corresponding values of the StringLengthValidatorAttribute.

Curious if you had tried supporting the Validation Application Block and came across the same conclusion?

Best Regards,

Patterns & Practices Guidance
Jan 14, 2009 at 9:59 AM
Edited Jan 14, 2009 at 10:00 AM
Hi David

I hadn't previously tried to add support for Validation Application Block. I thought maybe it was dead - it's not been updated since May 07, whereas the Dynamic Data-related stuff in System.ComponentModel.DataAnnotations is alive and evolving. Following your prompt I've had a good look at VAB and can see that it has certain advantages (e.g., it has a built-in validation runner as well as support for configuration defined in .config files or defined using attributes), so it would be great if xVal could give it client-side validation support in ASP.NET MVC.

VAB's official ASP.NET integration doesn't attempt to do any client-side validation at all, which may be related to the design limitation that you've mentioned.

Looking at the VAB source code, I think it would be quite possible to integrate VAB with xVal, with the proviso that you'd need to recompile VAB with [assembly: InternalsVisibleTo("xVal.RuleProviders.ValidationApplicationBlock")], then the integration might proceed as follows:
  • Rather than trying to detect VAB's attributes directly (because then you'd lose support for its XML configuration option), it may be better instead to use its PropertyValidationFactory type which will find all the validators attached to a type, respecting both XML and attribute-based configuration.
  • When it returns an AndCompositeValidator instance, you can just iterate over its Validators collection to get all the underlying validators. 
  • You can get the config information for each Validator instance by reading from the internal properties specific to that type. For example, for StringLengthValidator, read from its LowerBound and UpperBound properties
  • You don't need to support all VAB validators, just the subset that seems appropriate for client-side validation. VAB's validation runner will still take care of server-side validation of all possible validators. 
Of course, it isn't ideal that you'd need to enable [InternalsVisibleTo], because that would force people to use a custom build of Microsoft.Practices.EnterpriseLibrary.Validation. However, it doesn't appear that VAB is being actively developed by Microsoft so there isn't much disadvantage in using a custom build. Plus, anyone that's already using a custom build can easily add the [InternalsVisibleTo] assembly attribute. And if Microsoft does start developing VAB again, then perhaps they could take the hint and expose the bits necessary to integrate with other technologies.

What do you reckon?
Jan 14, 2009 at 2:41 PM
Hey Steve,

The Validation Application Block is part of Enterprise Library which has been updated twice a year every year since its creation, so I am not sure where you are seeing May 07. Patterns & Practices is probably starting work on Enterprise Library 5.0 as we speak, so the Validation Application Block is definitely alive and well.

VAB does have ASP.NET Integration through the PropertyProxyValidators, but these are server controls that require the webforms postback model. If simple, I thought it would be a nice option for EntLib Developers to use the VAB with MVC and xVal with the jQuery Validation support.

I had contemplated InternalsVisibleTo, which would definitely open up a whole new world of possibilities as you mention, but it leads us down a slippery path where the developer cannot use the signed assemblies from Microsoft. This opens up complications with larger clients with regard to support and just makes it a bit more difficult for others to implement by having to install the source, make the change, and having to build and deploy their own version. It is not a lot of work, but just makes the adoption that much more unlikely.

It would have been so much easier to just interrogate the attributes via reflection even though it would single out configuration as an option. I think the vast majority of users probably use attributes since it is easier to configure and maintain.

I think we just table this for now. I just wanted to see if you saw an easy way of doing this that I had missed, but it seems we are on the same page. Just to plant a seed, I will mention this in the EntLib Forums which they may be actively monitoring now for EntLib 5.0 ideas.

Best Regards,

Jan 14, 2009 at 3:14 PM
The Validation Application Block is part of Enterprise Library which has been updated 
> twice a year every year since its creation, so I am not sure where you are seeing May 07

Sorry, you're right - this is just a marketing/documentation issue. When I went looking for VAB (both originally when planning xVal and in response to your post), I searched Google for "validation application block". The top result is an MSDN page which states "Latest Release: Enterprise Library 3.1 – May 2007" (the other Google results look even older at first glance). also cites this page as the top result. It seemed authoritative! But yes, now I know there's a newer version I've been able to find it.

I agree with you about InternalsVisibleTo - it would be a hack and I don't personally want to create an IRuleProvider that way. Far better if the P&P group is willing to enhance EntLib 5.0 to expose enough configuration information to integrate with other systems. Otherwise, nobody can do client-side validation, which really isn't good enough in the modern world. Please do suggest this enhancement and let me know if you hear anything back.

Jan 14, 2009 at 3:44 PM
Oh, one more thought. Technically it would be possible now to detect the VAB attributes and discover their positional and named parameters, by using the introspection API in either Microsoft.Cci (the one that comes with FxCop) or the Mono.Cecil library. You could then discover what parameters were being supplied to (e.g.) StringLengthAttribute.

Of course, you'd need to cache the results because one can assume that introspection isn't fast. But again, this would be pretty hacky so is not something I intend to do myself...
Feb 3, 2009 at 10:17 PM
Edited Feb 3, 2009 at 10:22 PM
Steve and David,

Here is the beginnings of the Validation Application Block xVal Provider using introspection of Microsoft.Cci.dll that is bundled with FxCop 1.36.  I was able to build a StringLengthRule from VAB's StringLengthValidator.  Feel free to keep going with it if you have the time.  I don't think I'll be able to play with it anymore this week.

using System;
using System.Collections.Generic;
using System.Linq;
using xVal.Rules;
using xVal.RuleProviders;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;
using Microsoft.FxCop.Sdk;

namespace xVal.Providers
    public class ValidationBlockRulesProvider : IRuleProvider
        private AssemblyNode entityAssembly;

        public ValidationBlockRulesProvider()
            entityAssembly = AssemblyNode.GetAssembly(@"C:\Full\Path\To\Your\EntityAssemblyToInterrogate.dll");

        public RuleSet GetRulesFromType(Type type)
            var dictionary = new List<KeyValuePair<string, RuleBase>>();

            TypeNode typeNode = entityAssembly.GetType(Identifier.For(type.Namespace), Identifier.For(type.Name));
            foreach (Member m in typeNode.Members)
                //list of rules for this member
                var memberRules = new List<RuleBase>();

                foreach (var a in m.Attributes)
                    if (a.Type.FullName == typeof(NotNullValidatorAttribute).FullName)
                        memberRules.Add(new RequiredRule());
                    else if (a.Type.FullName == typeof(StringLengthValidatorAttribute).FullName)
                        memberRules.Add(ConstructStringLengthRule(m as PropertyNode, a));
            return new RuleSet(dictionary.ToLookup(x => x.Key, x => x.Value));

        /// public StringLengthValidator(int upperBound);
        /// public StringLengthValidator(int upperBound, bool negated);
        /// public StringLengthValidator(int lowerBound, int upperBound);
        /// public StringLengthValidator(int lowerBound, int upperBound, bool negated);
        /// public StringLengthValidator(int lowerBound, RangeBoundaryType lowerBoundType, int upperBound, RangeBoundaryType upperBoundType);
        /// public StringLengthValidator(int lowerBound, RangeBoundaryType lowerBoundType, int upperBound, RangeBoundaryType upperBoundType, bool negated);
        /// public StringLengthValidator(int lowerBound, RangeBoundaryType lowerBoundType, int upperBound, RangeBoundaryType upperBoundType, string messageTemplate);
        /// public StringLengthValidator(int lowerBound, RangeBoundaryType lowerBoundType, int upperBound, RangeBoundaryType upperBoundType, string messageTemplate, bool negated);

        private static StringLengthRule ConstructStringLengthRule(PropertyNode propertyNode, AttributeNode attributeNode)
            //could be upper or lower, depending on the overload used
            int firstArg = (int)((Literal) attributeNode.GetPositionalArgument(0)).Value;
            int? upperBound = null;
            int? lowerBound = null;

            Literal secondArg = (Literal)attributeNode.GetPositionalArgument(1);
            //if second argument is null or bool, then
            if (secondArg == null || secondArg.Value == typeof(bool))
                //first arg must be upperBound
                upperBound = firstArg;
            } else
                //first arg must be lowerBound
                lowerBound = firstArg;

                //find upper bound
                if (secondArg.Value == typeof(int))
                    upperBound = (int)secondArg.Value;
                } else
                    //ok it must be third arg
                    upperBound = (int)((Literal)attributeNode.GetPositionalArgument(2)).Value;
            return new StringLengthRule(lowerBound, upperBound);