Проблемы преобразования параметров ASP.NET MVC UpdateModel () - PullRequest
0 голосов
/ 23 августа 2011

Предупреждение: я относительно новичок в MVC и его парадигме, а также в некоторых ее внутренних принципах, но мне это довольно удобно. Это мое второе начальное MVC-приложение, и я немного озадачен тем, как решить «проблему», обнаруженную одним из наших тестеров.

Пользователи получают экран редактирования с датой вступления в силу ежедневных ставок LIBOR, поступающих из казначейства (в процентах). Показатели всегда находятся между 0 и 100, и поэтому я пытался ограничить этот диапазон, используя RangeAttribute в метаданных для одного из моих доменных объектов. Я определил диапазон так:

[Required, DisplayName("Published Rate"), Range(typeof(decimal), "0", "100")]
public object PublishedRate { get; set; }

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

"0,000000000000000000000000000000001"

Это приводит к сбою UpdateModel(); ModelState показывает эту ошибку (три раза для одного и того же значения ModelState, любопытно):

Ошибка преобразования параметра из типа System.String в тип System.Decimal.

Копание ошибок выявляет причину. Первая строка ниже - это то, что сообщается при проверке поля. Мне показалось любопытным, что это не всплыло из-за ошибок проверки модель (т.е. не отображалось в сводном списке проверки для модели):

"0.000000000000000000000000000000001 не является допустимым значением для десятичного числа." «Значение было слишком большим или слишком маленьким для десятичной дроби.»

System.Web.Mvc.ValueProviderResult.ConvertSimpleType() и System.ComponentModel.BaseNumberConverter.ConvertFrom() генерируют исключения.

Пользователь никогда не собирается вводить такое значение, как это, но я не возражаю знать, есть ли какие-либо механизмы, встроенные в MVC, которые могут или будут предотвращать это (то есть на стороне сервера). Кажется, что нет проблем с числами, подобными приведенным ниже, а кажется, что они ломаются только с очень маленькими.

"0,555555555555555555555555555555555"

В конце концов мне действительно нужно всего лишь 9 цифр точности. Столбец таблицы базы данных, поддерживающий эти значения, равен decimal(9,6). Я знаю, что мог бы реализовать пользовательский механизм связывания для своей модели и вручную собрать значения из запроса, но должно быть что-то немного проще, например пользовательский FilterAttribute или что-то, что может исправить значение, прежде чем его попытаться привязан к модели, я просто не уверен, что и ищу предложения.

Кажется, я вспомнил, что читал о некоторых проблемах с попыткой ограничить десятичные значения с помощью RangeAttribute, но я не могу вспомнить проблему. Возможно, вы, гуру MVC, можете пролить свет на ситуацию.

Ответы [ 2 ]

0 голосов
/ 24 августа 2011

Таким образом, после нескольких часов стука головы я остановился на следующей пользовательской модели переплета для десятичных дробей. Он проверяет, что все десятичные значения могут быть проанализированы перед их связыванием.

public class TreasuryIndexRateDecimalBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var providerResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        if (providerResult != null)
        {
            decimal value;
            if (!decimal.TryParse(providerResult.AttemptedValue, NumberStyles.Float, CultureInfo.CurrentCulture, out value))
            {
                // TODO: Decide whether to show an error
                // bindingContext.ModelState.AddModelError(bindingContext.ModelName, "error message");
                return 0m;
            }
            return Math.Round(value, 6);
        }
        return base.BindModel(controllerContext, bindingContext);
    }
}

Связывание установлено в Application_Start() для регистрации его для всех десятичных значений.

protected void Application_Start()
{
    ModelBinders.Binders.Add(typeof(decimal), new TreasuryIndexRateDecimalBinder());

    AreaRegistration.RegisterAllAreas();
    RegisterRoutes(RouteTable.Routes);
}

Если кто-то не придет с более интересным подходом, я думаю, что я буду придерживаться этого.

0 голосов
/ 24 августа 2011

Вы можете использовать атрибут Regex, чтобы содержать десятичное число с точностью до 9. Это также позволит вам добавить пользовательское сообщение, когда Regex завершится неудачно, например, «Ваше значение может иметь максимум 9 знаков после десятичного числа."или что-то подобное.Также, если у вас включена проверка на стороне клиента, Regex будет работать как на стороне клиента, так и на стороне сервера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...