Как привязать параметры URL к свойствам модели с разными именами - PullRequest
10 голосов
/ 14 декабря 2011

Хорошо, допустим, у меня есть такой URL, который отображается через HTTP-глагол GET на действие контроллера, которое у меня ниже:

GET /foo/bar?sort=asc&r=true

Как я могу связать это с моей моделью Bar на моем контроллере у меня есть следующие действия:

class Bar {
    string SortOrder { get; set; }
    bool Random { get; set; }
}

public ActionResult FooBar(Bar bar) {
    // Do something with bar
    return null;
}

Обратите внимание, что имена свойств не будут совпадать и не обязательно будут совпадать с именами параметров URL.Кроме того, это необязательные параметры URL.

Ответы [ 5 ]

12 голосов
/ 14 декабря 2011

Это не поддерживается "из коробки", но вы можете сделать это:

class BarQuery : Bar { 

   public string sort { get { return SortOrder; } set { SortOrder = value; } }
   public bool r { get { return Random; } set { Random = value; } }
}

public ActionResult FooBar(BarQuery bar) {
    // Do something with bar
}

Вы можете реализовать пользовательский IModelBinder, но намного проще сделать ручное отображение.Если вы можете изменить класс Bar, вы можете использовать этот атрибут:

class FromQueryAttribute : CustomModelBinderAttribute, IModelBinder { 

   public string Name { get; set; }

   public FromQueryAttribute() { }

   public FromQueryAttribute(string name) { 
      this.Name = name;
   }

   public override IModelBinder GetModelBinder() { 
      return this;
   }

   public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
      return controllerContext.HttpContext.QueryString[this.Name ?? bindingContext.ModelName];
   }
}

class Bar {

    [FromQuery("sort")]
    string SortOrder { get; set; }

    [FromQuery("r")]
    bool Random { get; set; }
}

public ActionResult FooBar(Bar bar) {
    // Do something with bar
    return null;
}
5 голосов
/ 14 декабря 2011

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

вариантов, которые вы получили:

  1. Сопоставьте имена входов с именами свойств модели ... но Вы сказали, что не можете этого сделать (по неизвестной причине).
  2. Написать пользовательскую модель Binder. *
  3. Используйте атрибут Bind с префиксом - хотя он все равно заставит вас вводить имена, близкие к именам свойств модели.

так в принципе, вы не можете делать именно то, что вы хотите.


Обновление:

Вы написали в комментарии, что свойства МОГУТ совпадать с именами параметров, поэтому вместо записи пользовательских атрибутов, которые, возможно, удастся выполнить связывание, просто напишите ViewModel (VM fromMVC ...), чтобы настроить имена параметров URL .

Команда разработчиков MVC не рекомендует написание пользовательского связующего для модели:

В общем, мы рекомендуем людям не писать пользовательские связующие модели, потому что их трудно понять правильно и они редко нужны
с здесь

3 голосов
/ 14 декабря 2011

У меня была такая же проблема давным-давно, и я использовал это стековое решение Андраса Золтана: Asp.Net MVC 2 - Привязать свойство модели к другому названному значению

Я установил атрибут ModelBinder в своем классе и BindAlias ​​в свойстве:

  [ModelBinder(typeof(DefaultModelBinderEx))]
  public class MyModel
  {
        [Required]
        [BindAlias("new")]
        public int? Amount { get; set; }

Если вы не можете изменить или не имеете доступа к файлу модели для установки Атрибутов, вы все равно можете создать пользовательское связующее звено модели, ИЛИ создать конкретный объект, который вы сопоставите с вашей моделью (AutoMapper полезен)

1 голос
/ 14 декабря 2011

Не существует бесплатной функции привязки моделей MVC.Net, которая дает вам то, что вы хотите из коробки.Когда мне нужно сделать что-то подобное, это действительно заставляет меня задуматься о моём моделировании, которое почти всегда заставляет меня создать ViewModel для привязки моего вида и EntityModel для хранилища репозитория.

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

Mapper.Map<Bar>(barViewModel);
1 голос
/ 14 декабря 2011

Вы можете реализовать IModelBinder для сопоставления входящих параметров с выбранным вами объектом при условии, что имена входящих параметров определены.В противном случае вам пришлось бы полагаться на порядок и / или тип параметров, чтобы вывести правильную привязку, что представляется очень плохим выбором.

...