Довольно давно я уже писал о локализации MVC3-сайтов, уделив достаточно большое внимание способу перевода валидационных сообщений на другие языки.
Однако недавно в проекте я столкнулся с одной ошибкой валидации, перевести которую оказалось не так просто. Вот пример этой ошибки:

Как нетрудно заметить, я просто ввел в числовое поле очень большое значение. При этом сам факт возникновения ошибки меня вполне устраивал (большие значение обрабатывать и не планировалось), а вот текст на «иностранном» тестеров слегка смутил :)
Stackoverflow по этому поводу ничего не ответил, поэтому пришлось искать решение своими силами.
Более простых способов, чем перегрузить model-binder для числовых значений мне в голову с ходу не пришло. Таким образом решение выродилось в модел-байндер и регистрацию его в global.asax:
//регистрация где-нибудь в районе Application_Start:
System.Web.Mvc.ModelBinders.Binders.Add(typeof(int), new NumericModelBinder());
System.Web.Mvc.ModelBinders.Binders.Add(typeof(int?), new NumericModelBinder());
System.Web.Mvc.ModelBinders.Binders.Add(typeof(byte), new NumericModelBinder());
System.Web.Mvc.ModelBinders.Binders.Add(typeof(byte?), new NumericModelBinder());
//...
//Собственно байндер:
/// <summary>
/// выдает локализованные ошибки о переполнении (слишком большое число, введенное в поле int)
/// </summary>
public class NumericModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
double parsedValue;
if (double.TryParse(value.AttemptedValue, out parsedValue))
{
double minValue = 0;
double maxValue = 0;
var modelType = Nullable.GetUnderlyingType(bindingContext.ModelType) ?? bindingContext.ModelType;
if (modelType == typeof(byte))
{
minValue = byte.MinValue;
maxValue = byte.MaxValue;
}
if (modelType == typeof(int))
{
minValue = int.MinValue;
maxValue = int.MaxValue;
}
if (modelType == typeof(short))
{
minValue = short.MinValue;
maxValue = short.MaxValue;
}
if (modelType == typeof(long))
{
minValue = long.MinValue;
maxValue = long.MaxValue;
}
if (modelType == typeof(Int64))
{
minValue = Int64.MinValue;
maxValue = Int64.MaxValue;
}
if ((minValue != 0 || maxValue != 0) && (parsedValue < minValue || parsedValue > maxValue))
{
var error = GetUserResourceString(controllerContext, "PropertyValueInvalid") ?? "The value '{0}' is invalid.";
bindingContext.ModelState.AddModelError(bindingContext.ModelName, string.Format(error, value.AttemptedValue, bindingContext.ModelMetadata.DisplayName));
}
}
return base.BindModel(controllerContext, bindingContext);
}
private static string GetUserResourceString(ControllerContext controllerContext, string resourceName)
{
string result = null;
if (!String.IsNullOrEmpty(ResourceClassKey) && (controllerContext != null) && (controllerContext.HttpContext != null))
{
result = controllerContext.HttpContext.GetGlobalResourceObject(ResourceClassKey, resourceName, CultureInfo.CurrentUICulture) as string;
}
return result;
}
}
Локализованные строки берутся, по аналогии с предыдущим постом, из соответствующего ресурса. В простых случаях можно, конечно, и просто «захардкодить» текст прямо внутри байндера, избавившись от функции `GetUserResourceString`.
Будет любопытно узнать, если кому-то еще это пригодиться :)
P.S. Чтобы добавить к этой ошибке еще и клиентскую валидацию, придется подправлять дефолтные адаптеры для jquery.validation. Мне это в данном случае показалось излишним, и для простоты последующих обновлений я решил не модифицировать jquery.validation а ограничиться в данном случае серверной валидацией.