1

I'm creating an mvc app in asp.net. I've created viewModel with dataAttribute Required on this member, in order to get Validation message when I post my model to my controller. This is working fine.

Now I want to override the Validate method in order to specify a translation for the errorMessage. I'm working with a custom framework to get translation for a key.

I have to override the Required dataAttribute in order to get it working with expressive annotation.

Here is the code

ViewModel

public class SocietyInformationViewModel
{
    [Required(ErrorMessage = "5614")]
    public string Name { get; set; }
}

I put the translationKey in my ErrorMessage

After that, I've created a custom ModelValidator and a custom ModelValidatorProvider

ModelValidator

public class LocalizableDataAnnotationsModelValidator : ModelValidator
{
    private ModelValidator _innerValidator;
    private ModelMetadata _metadata;

    public LocalizableDataAnnotationsModelValidator(ModelValidator innerValidator, ModelMetadata metadata, ControllerContext controllerContext)
        : base(metadata, controllerContext)
    {
        _innerValidator = innerValidator;
        _metadata = metadata;
    }

    public override IEnumerable<ModelValidationResult> Validate(object container)
    {
        Service.TranslationService LocalizationManager = new Service.TranslationService();

        // execute the inner validation which doesn't have localization
        var results = _innerValidator.Validate(container);

        // convert the error message (which should be the localization resource key) to the localized value through the ILocalizationResourceProvider
        return results.Select((result) =>
        {
            string message = result.Message;
            int key = 0;

            if (Int32.TryParse(result.Message, out key))
                message = LocalizationManager.Get(key, "");

            return new ModelValidationResult() { Message = string.Format(message, _metadata.DisplayName) };
        });
    }

    public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
    {
        Service.TranslationService LocalizationManager = new Service.TranslationService();
        var somerules = _innerValidator.GetClientValidationRules().ToList();

        foreach (var rule in somerules)
        {
            int key = 0;
            if (rule.ErrorMessage != null && rule.ErrorMessage.Length >= 3 && rule.ErrorMessage.Length <= 5 && Int32.TryParse(rule.ErrorMessage, out key))
                rule.ErrorMessage = LocalizationManager.Get(key, "");
        }

        return somerules;
    }
}

ModelValidatorProvider

public class LocalizableDataAnnotationsModelValidatorProvider : DataAnnotationsModelValidatorProvider
{
    public LocalizableDataAnnotationsModelValidatorProvider()
        : base()
    {
    }

    protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
    {
        var validators = base.GetValidators(metadata, context, attributes);
        var cnt = validators.Count();
        var result = new List<LocalizableDataAnnotationsModelValidator>();
        foreach (var validator in validators)
        {
            result.Add(new LocalizableDataAnnotationsModelValidator(validator, metadata, context));
        }
        return result;
    }
}

And now I call the RegisterModelProviders in the global.asax on applicationStart

private void RegisterModelProviders()
    {
        // register the model metadata provider
        //ModelMetadataProviders.Current = new LocalizableDataAnnotationsModelMetadataProvider();

        //// register the model validation provider
        var provider = ModelValidatorProviders.Providers.Where(p => p.GetType() == typeof(DataAnnotationsModelValidatorProvider)).FirstOrDefault();

        DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;

        if (provider != null)
        {
            ModelValidatorProviders.Providers.Remove(provider);
        }

        //ModelValidatorProviders.Providers.Clear();
        provider = new LocalizableDataAnnotationsModelValidatorProvider();
        ModelValidatorProviders.Providers.Add(provider);
    }

When doing like this, on execution, I've got the following exception

Validation type names in unobtrusive client validation rules must be unique. The following validation type was seen more than once: required

So I search on the web and I found this article with comments that say that I've to modify my web.config and set to false the ClientValidationEnabled key. I did it, and the error was gone, but my modelValidor is no more called...

I'm a little bit lost, any help is welcome

====== Update =======

After looking a lot on stack, I found that when using Ninject, it'will add NinjectDataAnnotationsModelValidatorProvider. That why I've got the message

The following validation type was seen more than once: required

So I try to remove NinjectDataAnnotationsModelValidatorProvider but I can't find any solution for that.

====== Update 2 =======

In order to fix previous problems, I download Ninject.Web.Mvc project on github and include it in my solution. Then, I remove this line (from the MvcModule.cs)

this.Kernel.Bind<ModelValidatorProvider>().To<NinjectDataAnnotationsModelValidatorProvider>();

I know it's not the best solution, but it's the only one that I've found

Community
  • 1
  • 1
dpfauwadel
  • 3,866
  • 3
  • 23
  • 40

1 Answers1

0

If multiple providers provide the same validators it will register the same rules multiple times that's why its causing an error.

Try this:

private void RegisterModelProviders()
{
    var provider = new LocalizableDataAnnotationsModelValidatorProvider();
    ModelValidatorProviders.Providers.Add(provider);
    DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
    provider.AddImplicitRequiredValidator = false;
}
jomsk1e
  • 3,585
  • 7
  • 34
  • 59
  • I don't have `provider.AddImplicitRequiredValidator = false;` So I try to put this in the constructor `public LocalizableDataAnnotationsModelValidatorProvider() : base() { AddImplicitRequiredAttributeForValueTypes = false; }` but this doesn't work. – dpfauwadel Nov 04 '16 at 07:09