Как привязать параметры URL к свойствам модели с разными именами

хорошо, допустим, у меня есть URL-адрес, который отображается через HTTP verb 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 ответов


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

параметры у вас есть:

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

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


обновление:

вы написали в комментарии, что свойства могут соответствовать именам параметров, поэтому вместо записи пользовательских атрибутов, которые, возможно, удастся выполнить привязку, просто напишите ViewModel (VM fromMVC...) для настройки имен параметров url.

написание пользовательской модели Binder не рекомендуется команда MVC:

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


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

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;
}

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

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

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

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


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


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

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

Mapper.Map<Bar>(barViewModel);