Пишем код

Заметки о .net разработке

Локализация сообщений о переполнении int в MVC3

without comments

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

Однако недавно в проекте я столкнулся с одной ошибкой валидации, перевести которую оказалось не так просто. Вот пример этой ошибки:

Как нетрудно заметить, я просто ввел в числовое поле очень большое значение. При этом сам факт возникновения ошибки меня вполне устраивал (большие значение обрабатывать и не планировалось), а вот текст на «иностранном» тестеров слегка смутил :)


Stackoverflow по этому поводу ничего не ответил, поэтому пришлось искать решение своими силами.

Более простых способов, чем перегрузить model-binder для числовых значений мне в голову с ходу не пришло. Таким образом решение выродилось в модел-байндер и регистрацию его в global.asax:

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

Локализованные строки берутся, по аналогии с предыдущим постом, из соответствующего ресурса. В простых случаях можно, конечно, и просто «захардкодить» текст прямо внутри байндера, избавившись от функции `GetUserResourceString`.

Будет любопытно узнать, если кому-то еще это пригодиться :)
P.S. Чтобы добавить к этой ошибке еще и клиентскую валидацию, придется подправлять дефолтные адаптеры для jquery.validation. Мне это в данном случае показалось излишним, и для простоты последующих обновлений я решил не модифицировать jquery.validation а ограничиться в данном случае серверной валидацией.

Опубликовать в Facebook
Опубликовать в Google Plus

Written by Shaddix

Июнь 23rd, 2012 at 6:31 пп

Posted in .net,MVC

Leave a Reply