Подтвердить что ты не робот

MVC Model Binding для коллекции, где коллекция не начинается с индекса 0

Я пытаюсь выполнить удаленную проверку на свойство элемента внутри коллекции. Валидация работает нормально в первом элементе коллекции. HTTP-запрос к методу проверки выглядит следующим образом:

/Validation/IsImeiAvailable?ImeiGadgets[0].ImeiNumber=123456789012345

Однако во втором пункте, где URL-адрес выглядит ниже, проверка не работает.

/Validation/IsImeiAvailable?ImeiGadgets[1].ImeiNumber=123456789012345

Теперь я уверен, что причиной этого является то, что привязка не работает в коллекции, которая не начинается с нулевого индекса.

Мой метод проверки имеет подпись, как показано ниже:

public JsonResult IsImeiAvailable([Bind(Prefix = "ImeiGadgets")] Models.ViewModels.ImeiGadget[] imeiGadget)

Поскольку я передаю элемент внутри коллекции, я должен так привязываться, но то, что я действительно передаю, - это всего лишь одно значение.

В любом случае я могу справиться с этим иначе, чем просто привязать его как обычную старую строку запроса.

Спасибо

Изменить: это быстрое исправление для получения переменной Imei, но я бы предпочел использовать привязку модели:

string imeiNumber = Request.Url.AbsoluteUri.Substring(Request.Url.AbsoluteUri.IndexOf("=")+1);

Изменить: Вот мой класс ImeiGadget:

public class ImeiGadget
{
    public int Id { get; set; }

    [Remote("IsImeiAvailable", "Validation")]
    [Required(ErrorMessage = "Please provide the IMEI Number for your Phone")]
    [RegularExpression(@"(\D*\d){15,17}", ErrorMessage = "An IMEI number must contain between 15 & 17 digits")]
    public string ImeiNumber { get; set; }
    public string Make { get; set; }
    public string Model { get; set; }
}
4b9b3361

Ответ 1

Вы можете написать настраиваемое связующее устройство:

public class ImeiNumberModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var modelName = bindingContext.ModelName;
        var request = controllerContext.HttpContext.Request;
        var paramName = request
            .Params
            .Keys
            .Cast<string>()
            .FirstOrDefault(
                x => x.EndsWith(modelName, StringComparison.OrdinalIgnoreCase)
            );

        if (!string.IsNullOrEmpty(paramName))
        {
            return bindingContext
                .ValueProvider
                .GetValue(request[paramName])
                .AttemptedValue;
        }

        return null;
    }
}

а затем примените его к действию контроллера:

public ActionResult IsImeiAvailable(
    [ModelBinder(typeof(ImeiNumberModelBinder))] string imeiNumber
)
{
    return Json(!string.IsNullOrEmpty(imeiNumber), JsonRequestBehavior.AllowGet);
}

Теперь часть ImeiGadgets[xxx] будет проигнорирована из строки запроса.

Ответ 2

Если вы отправляете на сервер одно значение для проверки, тогда ваш Action Method должен принимать только скалярный (однозначный) параметр, а не коллекцию. Тогда ваш URL-адрес будет выглядеть следующим образом (при условии, что таблица маршрутизации по умолчанию для {controller}/{action}/{id}:

/Validation/IsImeiAvailable?ImeiNumber=123456789012345

соответствующая подпись метода действия может выглядеть так:

/* note that the param name has to matchthe prop name being validated */
public ActionResult IsImeiAvailable(int ImeiNumber)

EDIT: которые затем можно использовать для поиска того, доступен ли этот идентификатор.

если вы хотите изменить имя параметра, вы можете изменить таблицу маршрутизации, но это другая тема.

Короче говоря, если вы хотите сделать проверку коллекции ImeiGadget, вы получите GET или POST полную коллекцию. Для одного значения не имеет смысла посылать или ожидать целую коллекцию.

UPDATE: Основываясь на новой информации, я бы посмотрел, где размещается атрибут удаленной проверки. Похоже, он может быть помещен на что-то вроде IEnumerable<IMEiGadgets>, например:

[Remote("IsImeiAvailable", "Validation", "'ImeiNumber' is invalid"]
public IEnumerable<ImeiGadget> ImeiGadgets { get; set;}

Можно ли переместить этот атрибут и изменить его вместо класса ImeiGadget, чтобы быть чем-то вроде этого?

[Remote("IsImeiAvailable", "Validation", "'ImeiNumber is invalid"]
public int ImeiNumber { get; set;}

В теории вам не нужно ничего менять на своих HTML-шаблонах или сценариях, чтобы получить эту работу, если вы также внесите изменения, предложенные в моем ответе выше. Теоретически.

Ответ 3

Если вы публикуете всю коллекцию, но имеете несущественный индекс, вы можете рассмотреть возможность привязки к словарю http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx

Если вы публикуете только один элемент или используете ссылку GET, вам следует внести изменения в

/Validation/IsImeiAvailable?ImeiNumber=123456789012345

и

public JsonResult IsImeiAvailable(string imeiNumber)

Ответ 4

Если вам не нужна эта функция привязки в во многих местах, и вы контролируете метод проверки IsImeiAvailable, то я думаю, что создание настраиваемого связующего объекта является над головой.

Почему бы вам не попробовать такое простое решение,

// need little optimization?
public JsonResult IsImeiAvailable(string imeiNumber)
{
  var qParam = Request.QueryString.Keys
     .Cast<string>().FirstOrDefault(a => a.EndsWith("ImeiNumber"));

  return Json(!string.IsNullOrEmpty(imeiNumber ?? Request.QueryString[qParam]), JsonRequestBehavior.AllowGet);
}