.NET MVC 3 Custom Decimal? Model Binder

2019-04-06 11:13发布

问题:

In my model, I have the following decimal? property:

public decimal? Budget { get; set; }

I realize that I need a custom model binder for decimals which Haack provided at the following link: http://haacked.com/archive/2011/03/19/fixing-binding-to-decimals.aspx.

I have modified his code so that if the value being passed in does contain a currency symbol and/or comma then I strip it and then try to convert it to a decimal. This works but being that my property is a nullable decimal type, I also want it to accept nothing and move along its merry way inserting a null into that column in my database. Right now it inserts a 0.00. I know I'm missing something in my code but am having a brain freeze.

Here's the binder code:

 public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
    ValueProviderResult valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
    ModelState modelState = new ModelState { Value = valueResult };
    object actualValue = null;
    object newValue = null;
    try
    {
        if (!string.IsNullOrEmpty(valueResult.AttemptedValue))
        {
            newValue = valueResult.AttemptedValue.Replace("$", "").Replace(",", "");
        }

        actualValue = Convert.ToDecimal(newValue, CultureInfo.CurrentCulture);
    }
    catch (FormatException e)
    {
        modelState.Errors.Add(e);
    }

    bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
    return actualValue;
}

Again, the goal is to have decimal? act like it usually does but if there is a value which contains a currency symbol and/or comma and it can be converted to a decimal then to return that.

Thanks

回答1:

In the try block, I think you need something like

string valToCheck = valueResult.AttemptedValue;
if(valToCheck == string.Empty)
{
    actualValue = null;
}
else
{
    actualValue = Convert.ToDecimal(valToCheck.Replace("$", string.Empty), CultureInfo.InvariantCulture);
 }

In your code, you are always setting actualValue to the result of ToDecimal().



回答2:

You're probably better off to utilize the built in support for handling NumberStyles. By doing this you can account for more than just the common dollar sign but can also handle Pounds, Yen, etc...

public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
    ValueProviderResult valueResult = bindingContext.ValueProvider
        .GetValue(bindingContext.ModelName);
    ModelState modelState = new ModelState { Value = valueResult };
    object actualValue = null;
    try
    {
        if(!string.IsNullOrWhiteSpace(valueResult.AttemptedValue))
            actualValue = Decimal.Parse(valueResult.AttemptedValue, NumberStyles.Currency, CultureInfo.CurrentCulture);
    }
    catch (FormatException e)
    {
        modelState.Errors.Add(e);
    }

    bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
    return actualValue;
}