Mvc: PropertyValueInvalid localization

Created on 23 Aug 2017  路  9Comments  路  Source: aspnet/Mvc

In the old ASP.NET MVC we could add App_GlobalResources with PropertyValueInvalid to overwrite the localization for The value '{0}' is invalid (see, e.g., https://stackoverflow.com/questions/1538873/how-to-replace-the-default-modelstate-error-message-in-asp-net-mvc-2)

What's the new way to do that in ASP.NET MVC Core? I cannot find a way in the docs :(

question

Most helpful comment

In ASP.NET Core MVC there's a new ModelBindingMessageProvider abstract base class that has all the various messages on it. You can use its default implementation, DefaultModelBindingMessageProvider, to set a function that generates a custom message, for example, one that retrieves a localized value.

You can do all this easily in MVC's "options" configuration in Startup.cs, like so:

c# services.AddMvc(options => { options.ModelBindingMessageProvider.SetAttemptedValueIsInvalidAccessor((v, p) => $"The value '{v}' is not valid for {p}."); });

BTW I wrote this without testing it, so give it a shot, and let me know if it's a bit wrong 馃槃

All 9 comments

In ASP.NET Core MVC there's a new ModelBindingMessageProvider abstract base class that has all the various messages on it. You can use its default implementation, DefaultModelBindingMessageProvider, to set a function that generates a custom message, for example, one that retrieves a localized value.

You can do all this easily in MVC's "options" configuration in Startup.cs, like so:

c# services.AddMvc(options => { options.ModelBindingMessageProvider.SetAttemptedValueIsInvalidAccessor((v, p) => $"The value '{v}' is not valid for {p}."); });

BTW I wrote this without testing it, so give it a shot, and let me know if it's a bit wrong 馃槃

@Eilon It's very cool that ASP.NET Core MVC now has a real extension point for this!
However, it would be even cooler if that code went through globalization by default ;)

@Eilon : Thanks for your helpful answer! However, I'd too love to see those messages go through the localization infrastructure like @fschmied pointed out.

@Eilon : Oh, and furthermore, it doesn't seem to work at all :( Just tried it...

Attached you find a repro sample based upon the Visual Studio ASP.NET MVC Core template. Go to the contact page, I've added a form there, make sure to clear the input field and press Submit -> it should either give "LOL LOL LOL" or "ROFL ROFL ROFL" (see Startup), however, it still displays the standard "The value '' is invalid." message.

Any ideas?

ModelBindingMessageProvider.zip

@SteveSandersonMS - you've worked in this area before, can you help @drauch out? Apparently my previous code example was incorrect.

Found the problem -> if there is no value given, the ValueMustNotBeNullAccessor is used instead of the AttemptedValueIsInvalidAccessor!

Glad you solved that. Apologies for missing the preceding message asking for help!

@SteveSandersonMS : There is still the issue on why those do not run through the localization infrastructure by default. Everybody has to do that themselves now...

There is still the issue on why those do not run through the localization infrastructure by default.

The localization infrastructure is opt-in, requiring e.g. calls to IMvcBuilder or IMvcCoreBuilder extension methods. It may have been possible to use an IStringLocalizerFactory when available, but that's rather complicated. Which keys would we use? What resources should be referenced?

One possible setup:
``` c#
public class SomeMvcOptionsSetup : IConfigureOptions
{
private readonly IStringLocalizerFactory _stringLocalizerFactory;

    public SomeMvcOptionsSetup()
    {
    }

    public SomeMvcOptionsSetup(IStringLocalizerFactory stringLocalizerFactory)
    {
        _stringLocalizerFactory = stringLocalizerFactory;
    }

    public void Configure(MvcOptions options)
    {
        options.ModelBindingMessageProvider.SetMissingKeyOrValueAccessor(() =>
        {
            if (_stringLocalizerFactory == null)
            {
                return Resources.KeyValuePair_BothKeyAndValueMustBePresent;
            }

            var stringLocalizer = _stringLocalizerFactory.Create(typeof(Startup));
            return stringLocalizer[Resources.KeyValuePair_BothKeyAndValueMustBePresent];
        });
    }
}
Then, add the following to your `Startup.ConfigureServices(...)` method:
``` c#
services.TryAddEnumerable(
    ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, SomeMvcOptionsSetup >());

Note Startup and Resources are sample classes from the application, not MVC.

Was this page helpful?
0 / 5 - 0 ratings