2

I have a variable name CountryId(Integer Type). If user provides a string or any random input to CountryId, the In-built DefaultBindingModel in ASP.Net throws an error :

The value '<script>gghghg</script>' is not valid for CountryId.

I want to override this message and provide my own text if the ModelState fails. I want a generic solution.

I've searched and tried many solutions, but they only worked for MVC applications, not webAPI.

public class IntegerModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        if (valueProviderResult == null)
        {
            return base.BindModel(controllerContext, bindingContext);
        }
         int i;

        return !int.TryParse(valueProviderResult.AttemptedValue.ToString(), out i) ? new ValidationResult("Failed") : ValidationResult.Success;

    }
}

And in my WebAPI.config :

ModelBinders.Binders.Add(typeof(int), new IntegerModelBinder());

Expected :

The value is not valid for CountryId.

Result :

The value '<script>gghghg</script>' is not valid for CountryId.
  • 1
    Dont use DefaultBindinModel in that case, also please throw in some code in thequestion – Code Name Jack Aug 21 '19 at 12:12
  • @PrasadTelkikar I know that the message is more clear, but the requirement is that EndUser should not be able to see the input value. – Anurag Maheshwari Aug 21 '19 at 16:08
  • @CodeNameJack I tried making my own BinderModel, but It doesn't work. I was making a resource file and added a field "PropertyValueInvalid The value '{0}' is not valid for {1}.". But no luck. – Anurag Maheshwari Aug 21 '19 at 16:17

3 Answers3

0

I think this link will helps you, and Option #3: Use a custom model binder could be to the point solution.

public class LocationModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, 
      ModelBindingContext bindingContext)
    {
        string key = bindingContext.ModelName;
        ValueProviderResult val = bindingContext.ValueProvider.GetValue(key);
        if (val != null)
        {
            string s = val.AttemptedValue as string;
            if (s != null)
            {
                return Location.TryParse(s);
            }
        }
        return null;
    }
}

now we need to wire up the model binder.

   public object  MyAction2(
        [ModelBinder(typeof(LocationModelBinder))]
        Location loc) // Use model binding to convert
    {
        // use loc...
    }

https://blogs.msdn.microsoft.com/jmstall/2012/04/20/how-to-bind-to-custom-objects-in-action-signatures-in-mvcwebapi/

0

Web API

For Web API you can replace the TypeConversionErrorMessageProvider to provide a custom message.

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        ModelBinderConfig.TypeConversionErrorMessageProvider = CustomTypeConversionErrorMessageProvider;

        // rest of init code
    }

    private string CustomTypeConversionErrorMessageProvider(HttpActionContext actionContext, System.Web.Http.Metadata.ModelMetadata modelMetadata, object incomingValue)
    {
        return $"The value is not valid for {modelMetadata.PropertyName}";
    }
}

Note the full qualification of the modelMetadata parameter of CustomTypeConversionErrorMessageProvider; if you don't do this, then the ModelMetadata class of System.Web.Mvc is referenced (due to the default usings in Global.asax.cs), instead of the one in System.Web.Http.Metadata, and you get an error:-

Error   CS0123  No overload for 'CustomTypeConversionErrorMessageProvider' matches delegate 'ModelBinderErrorMessageProvider'

MVC

For MVC, you can use the localization capability of MVC to replace those validation messages.

Basically, you create your own resource file, point MVC to that resource file using DefaultModelBinder.ResourceClassKey and in that resource file, specify your own text for the PropertyValueInvalid key.

There is a guide on how to do this here.

Aleks
  • 1,629
  • 14
  • 19
  • Thanx. I've already tried it but this works in MVC only, not working for WebAPI. – Anurag Maheshwari Aug 22 '19 at 09:47
  • @AnuragMaheshwari, don't mind... I just saw your answer where you found it :) – Aleks Aug 22 '19 at 23:38
  • Hi @Aleks , thanx for the answer, but I tried using your solution, and I'm facing an error " No overload for 'CustomTypeConversionErrorMessageProvider' matches delegate 'ModelBinderErrorMessageProvider' ". Kindly, provide me a solution for this. – Anurag Maheshwari Aug 23 '19 at 06:08
  • I found the answer here : https://stackoverflow.com/a/26782311/11727639 – Anurag Maheshwari Aug 23 '19 at 06:27
  • Hi @AnuragMaheshwari, that's strange. Was the method you used in your answer working? (it's more or less the same thing). What version of Microsoft.AspNet.WebApi.Core are you using? – Aleks Aug 23 '19 at 06:28
  • Hi @Aleks My solution is working fine. But I'm getting error in the below line : ModelBinderConfig.TypeConversionErrorMessageProvider = CustomTypeConversionErrorMessageProvider; And I'm using the version 5.2.3 of Microsoft.AspNet.WebApi.Core – Anurag Maheshwari Aug 23 '19 at 11:53
  • Hi @AnuragMaheshwari, I worked it out, please see my edit. I hadn't seen the conflict with `System.Web.Mvc.ModelBinder` and had to run up a new empty project to test. – Aleks Aug 24 '19 at 02:14
0

Thanks Everyone! But I got the solution. To Overrride this message for Int Validation in WebAPI, you just need to add the following snippet in Application_Start method in Global.asax.cs

ModelBinderConfig.TypeConversionErrorMessageProvider = (context, metadata, value) => {

            if (!typeof(int?).IsAssignableFrom(value.GetType()))
            {
                return "The Value is not valid for " + metadata.PropertyName;
            }
            return null;
        };