Попробуйте создать пользовательское связующее для модели , которое преобразует (скажем) "15 481" в десятичное число.
Результат, который вы ищете, заключается в проверке ввода как валюты, а не какдесятичное число, но у вас могут возникнуть другие потребности в очистке ввода перед привязкой модели, поэтому вы будете использовать интерфейс, описывающий действие Scrub.
public interface IScrubberAttribute
{
object Scrub(string modelValue, out bool success);
}
Далее, добавьте CurrencyScrubberAttribute
, который будет выполнять работупарсинг пользовательского ввода, чтобы увидеть, является ли он допустимым форматом валюты.В C # decimal.TryParse
есть перегрузка, которая принимает NumberStyle
и CultureInfo
, то есть как сделать проверку валюты.Вы заметите, что в настоящее время это работает только с американской валютой ($), но просто потребует установки CultureInfo для обработки других валют.
[AttributeUsage(AttributeTargets.Property)]
public class CurrencyScrubberAttribute : Attribute, IScrubberAttribute
{
private static NumberStyles _currencyStyle = NumberStyles.Currency;
private CultureInfo _culture = new CultureInfo("en-US");
public object Scrub(string modelValue, out bool success)
{
var modelDecimal = 0M;
success = decimal.TryParse(
modelValue,
_currencyStyle,
_culture,
out modelDecimal
);
return modelDecimal;
}
}
Использование нового CurrencyScrubberAttribute
, как показано ниже:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
[DisplayFormat(DataFormatString = "{0:C0}", ApplyFormatInEditMode = true)]
[CurrencyScrubber]
public decimal Price { get; set; }
}
Добавить модель переплета.В случае строго типизированной модели, такой как Product, ComplexTypeModelBinderProvider принимает вызов, а затем создает связыватель для каждого свойства.
public class ScrubbingModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
if (!context.Metadata.IsComplexType&&context.Metadata.PropertyName!=null)
{
// Look for scrubber attributes
var propName = context.Metadata.PropertyName;
var propInfo = context.Metadata.ContainerType.GetProperty(propName);
// Only one scrubber attribute can be applied to each property
var attribute = propInfo.GetCustomAttributes(typeof(IScrubberAttribute), false).FirstOrDefault();
if (attribute != null)
return new ScrubbingModelBinder(context.Metadata.ModelType, attribute as IScrubberAttribute);
}
return null;
}
}
Связыватель модели будет обрабатывать простые типы, которые имеютIScrubberAttribute
, но если по какой-либо причине мы не будем иметь дело с привязкой, мы передадим ее SimpleTypeModelBinder для ее обработки.
public class ScrubbingModelBinder : IModelBinder
{
IScrubberAttribute _attribute;
SimpleTypeModelBinder _baseBinder;
public ScrubbingModelBinder(Type type, IScrubberAttribute attribute)
{
if (type == null) throw new ArgumentNullException(nameof(type));
_attribute = attribute as IScrubberAttribute;
_baseBinder = new SimpleTypeModelBinder(type);
}
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null) throw new ArgumentNullException(nameof(bindingContext));
// Check the value sent in
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (valueProviderResult != ValueProviderResult.None)
{
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
// Attempt to scrub the input value
var valueAsString = valueProviderResult.FirstValue;
var success = true;
var result = _attribute.Scrub(valueAsString, out success);
if (success)
{
bindingContext.Result = ModelBindingResult.Success(result);
return Task.CompletedTask;
}
}
// If we haven't handled it, then we'll let the base SimpleTypeModelBinder handle it
return _baseBinder.BindModelAsync(bindingContext);
}
}
Добавьте ее в ConfigureServices
services.AddMvc(options =>
{
options.ModelBinderProviders.Insert(0, new ScrubbingModelBinderProvider());
});