May 7, 2018

RePost: Asp.Net Core 2.0 how to localize generic validation attribute messages

I want to localize client side validation messages that show as part of data annotations applied to model (Required, Compare etc) They are injected by MVC to JQuery validation engine.

Watch for this. Inspect DOM for your input control:

<input class="form-control input-validation-error" type="text" data-val="true" data-val-required id="Name" name="Name" value="" aria-required="true" aria-describedby="Name-error" aria-invalid="true">
If your data-val-required attr is empty like in above then your server side MVC validation messages configuration failed. It didn't provide any message. Hence JQuery validation will default to it's own hardcoded message "This field is required"

Bellow example works. Look for CustomValidationMetadataProvider.

What was frustrating is to distinct between:

 - Validation Attribute Error Messages Localization
Model Binding Error Messages Localization. 

In example Model binding error messages are server side validation messages you'll get if you disable client side validation.

There is one more scenario to consider in this example. When you create data annotation without explicit error message like this:

[Required]
public string Name

I didn't care about that scenario.
https://blogs.msdn.microsoft.com/mvpawardprogram/2017/05/09/aspnetcore-mvc-error-message/


Watch for this !
Remove AddDataAnnotationsLocalization from ConfigureService. This will silently override your CustomValidationMetadataProvider and try to obtain localization from Shared folder.

Here is modification from above link of metaprovider for few standard Data annotations.

 public class CustomValidationMetadataProvider : IValidationMetadataProvider
    {
        private ResourceManager resourceManager; private Type resourceType;
        public CustomValidationMetadataProvider(string baseName, Type type)
        {
            resourceType = type;
            resourceManager = new ResourceManager(typeof(SiteResources));
        }
        public void CreateValidationMetadata(
            ValidationMetadataProviderContext context)
        {
            AddRequiredForValueTypeIfMissing(context);
            foreach (var attribute in context.ValidationMetadata.ValidatorMetadata)
            {
                ValidationAttribute tAttr = attribute as ValidationAttribute;
                if (tAttr != null)
                {
                    if (tAttr is RequiredAttribute ||
                        tAttr is EmailAddressAttribute ||
                        tAttr is StringLengthAttribute)

                    {
                        var name = tAttr.GetType().Name;
                        if (resourceManager.GetString(name) != null)
                        {
                            tAttr.ErrorMessageResourceType = resourceType;
                            tAttr.ErrorMessageResourceName = name;
                            tAttr.ErrorMessage = null;
                        }
                    }
                }
            }
        }
        private void AddRequiredForValueTypeIfMissing(ValidationMetadataProviderContext context)
        {
            if (context.Key.ModelType.GetTypeInfo().IsValueType &&
                            context.ValidationMetadata.ValidatorMetadata
                                .Where(m => m.GetType() == typeof(RequiredAttribute)).Count() == 0)
                context.ValidationMetadata.ValidatorMetadata.
                    Add(new RequiredAttribute());
        }
    }


Here is quick snippet of standard referencing of JQuery Validation:

<environment include="Development">
    <script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
    <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
</environment>
<environment exclude="Development">
    <script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.14.0/jquery.validate.min.js"
            asp-fallback-src="~/lib/jquery-validation/dist/jquery.validate.min.js"
            asp-fallback-test="window.jQuery && window.jQuery.validator"
            crossorigin="anonymous"
            integrity="sha384-Fnqn3nxp3506LP/7Y3j/25BlWeA3PXTyT1l78LjECcPaKCV12TsZP7yyMxOe/G/k">
    </script>
    <script src="https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.6/jquery.validate.unobtrusive.min.js"
            asp-fallback-src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"
            asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive"
            crossorigin="anonymous"
            integrity="sha384-JrXK+k53HACyavUKOsL+NkmSesD2P+73eDMrbTtTk0h4RmOF8hF8apPlkp26JlyH">
    </script>
</environment>

In View :
@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

No comments:

Post a Comment