몇 가지 언급 :
- 문제는 유창함 검증과 아무런 공통점이 없다. Fluent Validation의 유무에 관계없이 재현/수정이 가능했습니다.
- 사용 된
DataFormatString
이 잘못되었습니다 (값 자리 표시자가 누락되었습니다). 실제로는 "{0:#,##0}"
이어야합니다.
- link에서
ModelBinder
접근 방식이 실제로 작동합니다. 나는 모델이 double?
을 사용하는 동안 decimal
데이터 형식으로 작성되었다는 것을 잊었을 것입니다. 따라서 double
및 double?
유형에 대해 다른 하나를 작성하고 등록해야합니다.
이제 주제가됩니다. 사실 두 가지 해결책이 있습니다. 둘 다 실제 문자열 변환에 대해 다음 헬퍼 클래스를 사용
using System;
using System.Collections.Generic;
using System.Globalization;
public static class NumericValueParser
{
static readonly Dictionary<Type, Func<string, CultureInfo, object>> parsers = new Dictionary<Type, Func<string, CultureInfo, object>>
{
{ typeof(byte), (s, c) => byte.Parse(s, NumberStyles.Any, c) },
{ typeof(sbyte), (s, c) => sbyte.Parse(s, NumberStyles.Any, c) },
{ typeof(short), (s, c) => short.Parse(s, NumberStyles.Any, c) },
{ typeof(ushort), (s, c) => ushort.Parse(s, NumberStyles.Any, c) },
{ typeof(int), (s, c) => int.Parse(s, NumberStyles.Any, c) },
{ typeof(uint), (s, c) => uint.Parse(s, NumberStyles.Any, c) },
{ typeof(long), (s, c) => long.Parse(s, NumberStyles.Any, c) },
{ typeof(ulong), (s, c) => ulong.Parse(s, NumberStyles.Any, c) },
{ typeof(float), (s, c) => float.Parse(s, NumberStyles.Any, c) },
{ typeof(double), (s, c) => double.Parse(s, NumberStyles.Any, c) },
{ typeof(decimal), (s, c) => decimal.Parse(s, NumberStyles.Any, c) },
};
public static IEnumerable<Type> Types { get { return parsers.Keys; } }
public static object Parse(string value, Type type, CultureInfo culture)
{
return parsers[type](value, culture);
}
}
사용자 정의 IModelBinder
을이 링크 된 접근 방식의 수정 된 버전입니다.
protected void Application_Start()
{
NumericValueBinder.Register();
// ...
}
사용자 정의 TypeConverter
이를 : 당신이 필요로하는 모든이 Application_Start
에 등록하는 것입니다
using System;
using System.Web.Mvc;
public class NumericValueBinder : IModelBinder
{
public static void Register()
{
var binder = new NumericValueBinder();
foreach (var type in NumericValueParser.Types)
{
// Register for both type and nullable type
ModelBinders.Binders.Add(type, binder);
ModelBinders.Binders.Add(typeof(Nullable<>).MakeGenericType(type), binder);
}
}
private NumericValueBinder() { }
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
var modelState = new ModelState { Value = valueResult };
object actualValue = null;
if (!string.IsNullOrWhiteSpace(valueResult.AttemptedValue))
{
try
{
var type = bindingContext.ModelType;
var underlyingType = Nullable.GetUnderlyingType(type);
var valueType = underlyingType ?? type;
actualValue = NumericValueParser.Parse(valueResult.AttemptedValue, valueType, valueResult.Culture);
}
catch (Exception e)
{
modelState.Errors.Add(e);
}
}
bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
return actualValue;
}
}
: 그것은 모든 숫자 유형과 각각의 nullable 형식을 처리하는 하나의 클래스입니다 ASP.NET MVC 5에만 국한되는 것은 아니지만 DefaultModelBinder
은 문자열 변환을 연결된 TypeConverter
(다른 NET UI 프레임 워크와 비슷 함)에 위임합니다. 실제로이 문제는 숫자 형식에 대한 TypeConverter
클래스가 Convert
클래스를 사용하지 않고 을 제외한 NumberStyles
을 전달하는 Parse
오버플로로 인해 발생합니다.
다행스럽게도 System.ComponentModel
은 확장 가능 Type Descriptor Architecture을 제공하여 맞춤 TypeConverter
을 연결할 수 있습니다. 배관 부분은 다소 복잡합니다 (ICustomTypeDescriptor
구현을 제공하기 위해 사용자 정의 TypeDescriptionProvider
을 등록해야합니다. 사용자 정의 TypeConverter
을 최종적으로 반환합니다).하지만 대부분의 내용을 기본 객체에 위임하는 제공된 기본 클래스의 도움으로 구현 다음과 같습니다
using System;
using System.ComponentModel;
using System.Globalization;
class NumericTypeDescriptionProvider : TypeDescriptionProvider
{
public static void Register()
{
foreach (var type in NumericValueParser.Types)
TypeDescriptor.AddProvider(new NumericTypeDescriptionProvider(type, TypeDescriptor.GetProvider(type)), type);
}
readonly Descriptor descriptor;
private NumericTypeDescriptionProvider(Type type, TypeDescriptionProvider baseProvider)
: base(baseProvider)
{
descriptor = new Descriptor(type, baseProvider.GetTypeDescriptor(type));
}
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
return descriptor;
}
class Descriptor : CustomTypeDescriptor
{
readonly Converter converter;
public Descriptor(Type type, ICustomTypeDescriptor baseDescriptor)
: base(baseDescriptor)
{
converter = new Converter(type, baseDescriptor.GetConverter());
}
public override TypeConverter GetConverter()
{
return converter;
}
}
class Converter : TypeConverter
{
readonly Type type;
readonly TypeConverter baseConverter;
public Converter(Type type, TypeConverter baseConverter)
{
this.type = type;
this.baseConverter = baseConverter;
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return baseConverter.CanConvertTo(context, destinationType);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
return baseConverter.ConvertTo(context, culture, value, destinationType);
}
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return baseConverter.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string)
{
try { return NumericValueParser.Parse((string)value, type, culture); }
catch { }
}
return baseConverter.ConvertFrom(context, culture, value);
}
}
}
(예, 순서 상용구 코드를 많이 한 필수 줄을 추가하기 위해 다른 측면에서, DefaultModelBinder
이미 않기 때문에 nullable 형식을 처리 할 필요가 없습니다
: 그!
첫 번째 접근법과 마찬가지로, 등록 만하면됩니다.
protected void Application_Start()
{
NumericTypeDescriptionProvider.Register();
// ...
}
유형을 문자열로 변경 한 다음 이중 필드 인 백킹 필드를 사용하고 getter 및 setter가 변환을 수행하도록 고려 했습니까? XAML 응용 프로그램에서 변환기를 사용하는 것처럼 처리하는 것이 더 좋은 방법 인 것처럼 느껴지지만이 컨텍스트에서이를 수행하는 방법을 모르거나 ...이 문제를 해결할 수 있습니다. http : // stackoverflow. com/questions/29975128/asp-net-mvc-data-annotation-for-currency-format – Sinaesthetic
FluentValidation은 어디에서 사용할 수 있습니까? 'ModelState'의 오류입니까, 아니면 AbstractValidator가 오류를 일으 킵니까? – krillgar
빈 유효성 검사기 코드를 추가했습니다 – gls123