C# ASP.NET Core ModelBinder не обновляет модель

Я создал ModelBinder, который срабатывает только если объект имеет [Decimal] атрибут назначен, но по какой-то причине, несмотря на то, что он фактически очищает данные, он не обновляет опубликованную модель.

Интересно, может ли кто-нибудь увидеть из моего кода ниже, где я могу ошибаться.

Startup.cs

public void ConfigureServices(IServiceCollection serviceCollection)
{
    serviceCollection.AddMvc(config => config.ModelBinderProviders.Insert(0, new DecimalModelBinderProvider()));        
}

DecimalModelBinderProvider.cs

public class DecimalModelBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext modelBinderProviderContext)
    {
        if (modelBinderProviderContext == null)
        {
            throw new ArgumentNullException(nameof(modelBinderProviderContext));
        }

        if (!modelBinderProviderContext.Metadata.IsComplexType)
        {
            try
            {
                var propertyName = modelBinderProviderContext.Metadata.PropertyName;

                var property = modelBinderProviderContext.Metadata.ContainerType.GetProperty(propertyName);

                if (property != null)
                {
                    var attribute = property.GetCustomAttributes(typeof(DecimalAttribute), false).FirstOrDefault();

                    if (attribute != null)
                    {
                        return new DecimalModelBinder(modelBinderProviderContext.Metadata.ModelType, attribute as IDecimalAttribute);
                    }
                }
            }
            catch (Exception exception)
            {
                var message = exception.Message;

                return null;
            }
        }

        return null;
    }
}

DecimalModelBinder.cs

public class DecimalModelBinder : IModelBinder
{
    private readonly IDecimalAttribute _decimalAttribute;

    private readonly SimpleTypeModelBinder _simpleTypeModelBinder;

    public DecimalModelBinder(Type type, IDecimalAttribute decimalAttribute)
    {
        if (type == null)
        {
            throw new ArgumentNullException(nameof(type));
        }

        _decimalAttribute = decimalAttribute;

        _simpleTypeModelBinder = new SimpleTypeModelBinder(type);
    }

    public Task BindModelAsync(ModelBindingContext modelBindingContext)
    {
        if (modelBindingContext == null)
        {
            throw new ArgumentNullException(nameof(modelBindingContext));
        }

        var valueProviderResult = modelBindingContext.ValueProvider.GetValue(modelBindingContext.ModelName);

        if (valueProviderResult != ValueProviderResult.None)
        {
            modelBindingContext.ModelState.SetModelValue(modelBindingContext.ModelName, valueProviderResult);

            var value = valueProviderResult.FirstValue;

            bool success;

            var result = _decimalAttribute.Decimal(value, out success);

            if (success)
            {
                modelBindingContext.Result = ModelBindingResult.Success(result);

                return Task.CompletedTask;
            }
        }

        return _simpleTypeModelBinder.BindModelAsync(modelBindingContext);
    }
}

IDecimalAttribute.cs

public interface IDecimalAttribute
{
    object Decimal(string value, out bool success);
}

DecimalAttribute.cs

[AttributeUsage(AttributeTargets.Property)]
public class DecimalAttribute : Attribute, IDecimalAttribute
{
    public object Decimal(string value, out bool success)
    {
        var tryModelValue = string.IsNullOrEmpty(value) ? "0.00" : value.Replace("£", "").Replace("%", "");

        decimal @decimal;

        success = decimal.TryParse(tryModelValue, out @decimal);

        return @decimal;
    }
}

Test.cs

public class Test
{
    [Display(Name = "Name", Description = "Name")]
    public string Name { get; set; }

    [Decimal]
    [Display(Name = "Amount", Description = "Amount")]
    public double Amount { get; set; }
}

HomeController

[ValidateAntiForgeryToken]
[HttpPost]
public IActionResult Index(Test test)
{
    if (ModelState.IsValid)
    {

    }

    return View(test);
}

Для целей тестирования я введу значение £252,83 в поле Сумма и отправлю форму.

Если я тогда поставлю точку торможения на линию var value = valueProviderResult.FirstValue; Я вижу, что это значение £252,83, и если я поставлю точку останова на линии modelBindingContext.Result = ModelBindingResult.Success(result); Я вижу, что результат 252.83M,

Однако, если я перейду к следующему коду и установлю точку останова на строке if (ModelState.IsValid) действительное состояние ложно, и если я проверяю модель test предмет Amount это 0.

Если кто-то может помочь, это будет высоко ценится:-)

1 ответ

Попробуйте еще раз проверить ModelState Error, свойство Amount должно быть недопустимым, и должно быть исключение.

Я предполагаю, что это должно быть InvalidCastException. Я заметил, что свойство Amount в классе Test имеет значение Double, пока вы создаете десятичное число в своем атрибуте DecimalAttribute.

Таким образом, встроенная модель Binder, обрабатывающая класс Test (должен быть ComplexTypeModelBinder), не может установить свойство Amount, так как оно имеет другой тип.

Другие вопросы по тегам