Tag Archives: ModelBinder

“The value ‘NaN’ is not valid.” – The ModelBinder way

In my previous post I described how to solve “The value ‘NaN’ is not valid.” when an int parameter contains NaN. My colleauge then convinced me to solve this with a custom ModelBinder instead. So, here is the solution.

First we create a custom modelbinder.

public class IntNanModelBinder : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

            if (string.IsNullOrWhiteSpace(valueProviderResult.FirstValue) || valueProviderResult.FirstValue == "NaN") 
            {
                bindingContext.Result = ModelBindingResult.Failed();
            } else if (Int32.TryParse(valueProviderResult.FirstValue, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out var intValue))
            {
                bindingContext.Result = ModelBindingResult.Success(intValue);
            } else
            {
                throw new Exception($"Parameter '{bindingContext.ModelName}' with value '{valueProviderResult.FirstValue}' is not an int.");
            }

            return Task.CompletedTask;
        }
    }

This can now be used directly in your endpoint by

[HttpGet]
        [Route("list")]
        public IActionResult List([ModelBinder(BinderType = typeof(IntNanModelBinder))] int skip = 0, int take = 20)
        {
            // Code
        }

But we want to use this on all our endpoints where we have int as parameters. So we need to create a ModelBinderProvider and add it in our startup.

public class IntNanModelBinderProvider : IModelBinderProvider
    {
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (context.Metadata.ModelType == typeof(int))
            {
                return new BinderTypeModelBinder(typeof(IntNanModelBinder));
            }
            return null;
        }
    }

And in ConfigureServices in Startup.cs

services.AddMvc(c =>
            {
                c.ModelBinderProviders.Insert(0, new IntNanModelBinderProvider());
            });

And happy days, it works magically.