0

asp.net-core-mvc

I have a ViewModel with one decimal property on it:

public class RdoViewModel
{
    [DisplayFormat(DataFormatString = "{0:C0}", ApplyFormatInEditMode = true)]
    public decimal Balance { get; set; } = 100000;
}

Here are my controller methods.

public IActionResult Rdo()
{
    var vm = new RdoViewModel();
    vm.Balance = 150000;
    return View(vm);
}
[HttpPost]
public IActionResult Rdo(RdoViewModel vm)
{
    var balance = vm.Balance;
    return View(vm);
}

When I submit the form, MVC model binding can't figure out how to convert the string $150,000 back to 150000.

I can't seem to find any other questions about this topic. What is everyone else doing?

Terrence
  • 2,732
  • 2
  • 18
  • 12
  • Does this answer your question? [Data Annotation for currency format not working](https://stackoverflow.com/questions/39600688/data-annotation-for-currency-format-not-working) – Ryan Wilson Aug 02 '22 at 17:31
  • No, the Display formatting works great, showing $150,000. Its getting back to decimal to ModelBinding can work is the problem. – Terrence Aug 02 '22 at 17:58
  • I did read through it, but mentally blocked out the part about creating a custom model binder. Hard to believe everyone doing this is creating custom model binders. Thanks for your input. – Terrence Aug 02 '22 at 20:03
  • Could you please share how you are submitting the value from your client side? Need to figure out this issue on the client side. Precision may not be managed this way on the backend. – Md Farid Uddin Kiron Aug 03 '22 at 06:19
  • ```@model RdoViewModel @using (Html.BeginForm()) { } ```Am unable to edit the post and place the view code. – Terrence Aug 03 '22 at 15:15

1 Answers1

0

Ok, here are the 3 steps to create a Custom Decimal Model Binder

  1. Create the model binder.
public class CustomDecimalModelBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType == typeof(decimal) || bindingContext.ModelType == typeof(decimal?))
        {
            var valueToParse = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            if (valueToParse != null && valueToParse.Length > 0)
            {
                decimal parsedDecimal = 0;
                Decimal.TryParse(valueToParse.ToString(), NumberStyles.Any, CultureInfo.CurrentCulture, out parsedDecimal);
                bindingContext.Result = ModelBindingResult.Success(parsedDecimal);
            }
        }

        return Task.CompletedTask;
    }
}

  1. Create a Model Binder Provider
public class CustomModelBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        if (context.Metadata.ModelType == typeof(decimal))
            return new CustomDecimalModelBinder();

        return null;
    }
}
  1. Wire it up in your Startup.cs ConfigureServices method
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
    {
        options.ModelBinderProviders.Insert(0, new CustomModelBinderProvider());
    });
Terrence
  • 2,732
  • 2
  • 18
  • 12