jgauffin / griffin.mvccontrib

A contribution project for ASP.NET MVC3
http://blog.gauffin.org/tag/griffin-mvccontrib/
GNU Lesser General Public License v3.0
83 stars 40 forks source link

Client validation for custom validation attributes doesn't work #25

Open escobar5 opened 12 years ago

escobar5 commented 12 years ago

I'm having a problem using localization,

using LocalizedModelValidatorProvider breaks client validation of custom validation attributes.

The way to register the client validation for the custom attribute is by registering an adapter in DataAnnotationsModelValidatorProvider, but as we cleared all ModelValidatorProviders to add LocalizedModelValidatorProvider then client validation is not working anymore.

I'm trying to use Data Annotations Extensions from: http://dataannotationsextensions.org/ and for example client validation for Email attribute does not work (But server validation do work)

And this is the way they register the adapters: DataAnnotationsModelValidatorProvider.RegisterAdapter

Is there any solution for this problem?

Thanks

jefflaia commented 11 years ago

I've found a way to let it work. in your Application_Start don't clear ModelValidatorProviders.provoders, and don't add LocalizedModelValidatorProvider to Providers collection, just set the ModelMetadataProviders.Current to LocalizedModelMetadataProvider.

The follow example code will be called by Application_Start() in Global.asax.cs

private void SetupLocalizationProviders() { //ModelValidatorProviders.Providers.Clear(); // Don't execute this for customized DataAnnotation work ModelMetadataProviders.Current = new LocalizedModelMetadataProvider(); //ModelValidatorProviders.Providers.Add(new LocalizedModelValidatorProvider()); // Don't execute this for customized DataAnnotation work }

mpumcubido commented 11 years ago

Hi,

I tried your fix but actually the localization is not working anymore. Just the default texts are selected, not the ones from the database.

Is there a real fix how to get the SQL Server Provider working with Client Validation?

jgauffin commented 11 years ago

The code is available here: https://github.com/jgauffin/griffin.mvccontrib/blob/master/source/Griffin.MvcContrib/Localization/LocalizedModelValidatorProvider.cs

Feel free to try to provide a fix.

jefflaia commented 11 years ago

Hi jgauffin, I noticed in your code the class ValidationAttributeAdapterFactory constructor calls MapDefaultRules(), only init the built-in Model Client Validation Rules. can you provide a way to add more client validation rules for custom attributes?

jefflaia commented 11 years ago

step 1: modify the class LocalizedModelValidatorProvider, add a property as following code:

    public ValidationAttributeAdapterFactory ClientValidationRuleFactory
    { 
        get 
        {
            return _adapterFactory;
        } 
    }

step 2: add helper class in your MVC project to extend the client validation rules, the following example code is for DataAnnotationsExtensions and MVC Foolproof Validation:

public static class ClientValidationRuleFactoryHelper
{
    public static void MapClientValidationRules(ValidationAttributeAdapterFactory factory)
    {
        MapExtensionClientValidationRules(factory);
        MapFoolProofClientValidationRules(factory);
    }

    private static void MapExtensionClientValidationRules(ValidationAttributeAdapterFactory factory)
    {
        AddDelegateRule<EmailAttribute>(factory, (attribute, errMsg) =>
        {
            return new[]
                {
                    new ModelClientValidationEmailRule(errMsg)
                };
        });

        AddDelegateRule<MaxAttribute>(factory, (attribute, errMsg) =>
        {
            var attr = (MaxAttribute)attribute;
            return new[]
                {
                    new ModelClientValidationMaxRule(errMsg, attr.Max)
                };
        });

        // ---- other attributes client validation rules

    }

    private static void MapFoolProofClientValidationRules(ValidationAttributeAdapterFactory factory)
    {
        AddDelegateRule<GreaterThanAttribute>(factory, (attribute, errMsg) =>
        {
            var attr = (ContingentValidationAttribute)attribute;

            var rule = new ModelClientValidationRule() { ErrorMessage = errMsg, ValidationType = attr.ClientTypeName.ToLower() };

            foreach (var pair in attr.ClientValidationParameters)
            {
                rule.ValidationParameters[pair.Key] = pair.Value;
            }

            return new[]
                {
                    rule
                };
        });

        // ---- other attributes client validation rules
    }

    private static void AddDelegateRule<T>(ValidationAttributeAdapterFactory factory,
        Func<ValidationAttribute, string, IEnumerable<ModelClientValidationRule>> func)
        where T : ValidationAttribute
    {
        factory.Map<T>(new DelegateValidationAttributeAdapterFactory(func));
    }
}

Step 3: in Global.asax.cs file:

    private void SetupLocalizationProviders()
    {
        var provider = ModelValidatorProviders.Providers.Where(p => p.GetType() == typeof(DataAnnotationsModelValidatorProvider)).FirstOrDefault();
        if (provider != null)
        {
            ModelValidatorProviders.Providers.Remove(provider);
        }
        ModelMetadataProviders.Current = new LocalizedModelMetadataProvider();
        var localProvider = new LocalizedModelValidatorProvider();
        ModelValidatorProviders.Providers.Add(localProvider);

        //Register Client Validation Rules
        ClientValidationRuleFactoryHelper.MapClientValidationRules(localProvider.ClientValidationRuleFactory);
    }
jgauffin commented 11 years ago

thank you. :) I'll merge that code asap

sarae commented 11 years ago

Hi, The griffin.MvcContrib is a clean solution for localization :) I have the same problem with foolproof and DataAnnotationExtensions.

When can I get the new version?

Thank you!