Localizing ModelBinding Error Messages

ModelBinding error message's are similar to ValidationAttribute error messages in terms of validating user input, but they can't be localized in a similar way.

If we enter a text instead of a number we will see ModelBinding error message.

model binding error messages

ModelBinding error messages cannot be localized like ValdiationAttributes. But it can be localized by calling ModelBindingMessageProvider and setting values of localized messages in MvcOptions configurations.

Inside “Utilities” folder, create a new static class named “MvcOptionsExtensions” and create an extension method AddModelBindingMessagesLocalizer to extend IMvcBuilder:

MvcOptionsExtension.cs
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using MyTrips.Resources;
using System.Reflection;

namespace MyTrips.Utilities
{
    public static class MvcOptionsExtension
    {
        /// <summary>
        /// localize ModelBinding messages, e.g. when user enters string value instead of number...
        /// these messages can't be localized like data attributes
        /// </summary>
        /// <param name="mvc"></param>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IMvcBuilder AddModelBindingMessagesLocalizer
            (this IMvcBuilder mvc, IServiceCollection services)
        {
            return mvc.AddMvcOptions(o =>
            {
                var type = typeof(MyDataAnnotations);
                var assemblyName = new AssemblyName(type.GetTypeInfo().Assembly.FullName);
                var factory = services.BuildServiceProvider().GetService<IStringLocalizerFactory>();
                var localizer = factory.Create("MyDataAnnotations", assemblyName.Name);

                o.ModelBindingMessageProvider
                    .SetAttemptedValueIsInvalidAccessor((x, y) => localizer["'{0}' is not a valid value for '{1}'", x, y]);

                o.ModelBindingMessageProvider
                    .SetValueMustBeANumberAccessor((x) => localizer["'{0}' must be a number.", x]);
            });
        }
    }
}

Based on the solution in stackoverflow.com: https://stackoverflow.com/a/41669552/5519026

Call the extension method from startup file next to AddMvc():

startup.cs
services.AddMvc()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
    .AddViewLocalization(o=>o.ResourcesPath = "Resources")
    .AddModelBindingMessagesLocalizer(services)
    .AddDataAnnotationsLocalization(o=> {
        var type = typeof(ViewResource);
        var assemblyName = new AssemblyName(type.GetTypeInfo().Assembly.FullName);
        var factory = services.BuildServiceProvider().GetService<IStringLocalizerFactory>();
        var localizer = factory.Create("ViewResource", assemblyName.Name);
        o.DataAnnotationLocalizerProvider = (t, f) => localizer;
    })
    .AddRazorPagesOptions(o => {
        o.Conventions.Add(new CultureTemplateRouteModelConvention());
    });

Then add related localized error messages to “ViewResource.xx.resx” files and run the project, input string into the price field and submit the form, you will see localized model binding error message.

localized modelbinding error message

Next : Configuring Client Side Validation

Demo Project: My trips application

Source code on github: MyTrips