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, так как оно имеет другой тип.