2010-02-16 3 views
7

У меня есть то, что я думаю, это несколько нормальная ситуация, когда мне нужно привязать сообщения формы к модели «порядок». Эта модель имеет несколько уровней информации к нему:DefaultModelBinder Проблема с вложенными уровнями + другие связующие

Order.Billing.FirstName 
Order.Billing.Address.City 
Order.Billing.Address.Country 

Использование DefaultModelBinder, если я отправляю форму в действии, которое принимает эту модель Order как парам, следующие поля JustWork (TM):

<%=Html.TextBox("Billing.FirstName")%> 
<%=Html.TextBox("Billing.Address.City")%> 

Это поле не:

<%=Html.TextBox("Billing.Address.Country")%> 

морщинка у меня есть с собственностью страны. В нашем случае Address.Country возвращает экземпляр класса Country (ISO2/3/логика имени/кода). Это не строка. Не удивительно, что он не работает по умолчанию.

Моей первой мыслью было создать CountryModelBinder (inherit DefaultModelBinder) и ModelBinders.Binders.Добавить его в тип страны. Когда я это делаю, CountryModelBinder никогда не будет вызван в scenerio выше.

Моей второй мыслью было создать AddressModelBinder (inherit DefaultModelBinder) и привязать его к нашему типу адреса. Хотя вызов вызван, вызов SetProperty для «Страны» имеет пустое значение, хотя в форме вывешено поле «Billing.Address.Country».

После некоторого вмешательства, похоже, что поведение привязки модели вызывает только CreateModel, когда модель является классом верхнего уровня, которое требуется действию, а все другие связующие имеют свой BindPropery/SetProperty, который называется дочерними свойствами.

Другими словами, если я создаю привязку к модели для Order, OrderAddress (Billing), Address и Country. Для действия, которое принимает порядок, вызывается только OrderModelBinder.CreateModel. ORDERAddress и Address.BindProperty/SetProperty вызываются для некоторых вещей, и иногда аргумент значения SetProperty пуст, если он явно размещен в имени, которое соответствует другим сопоставлениям свойств поля.

Достаточно просто добавить код в OrderModelBinder, чтобы вытащить Billing.Address.Country из Request.Form. Но у меня есть несколько моделей, которые используют Address, и все они выглядят сломанными.

Что мне здесь не хватает? Есть ли способ заставить CountryModelBinder фактически получить вызов в этом случае? Я думаю, что CountryModelBinder следует вызвать, когда Billing.Address.Country сопоставляется с свойством Country связующего адреса.

+0

это может вам помочь: http://stackoverflow.com/questions/2462506/model-binding-with-nested-child-models-and-partialviews-in-asp-net-mvc – Will

+0

У меня такая же проблема с вложенной структурой модели, мне кажется, что свойства на верхнем уровне и один уровень вниз становятся связанными, но все, что ниже, похоже, просто игнорируется. Это нормальное поведение модельного связующего? Кажется довольно произвольным поведением. – UpTheCreek

ответ

0

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

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

Модели:

public class SimpleModel 
    { 
     public string Value { get; set; } 
     public int Other { get; set; } 
    } 

    public class ComplexModel 
    { 
     public SimpleModel Complexity {get;set;} 
     public string StrVal { get; set; } 
    } 

некоторые Связующее:

public class MBinder : IModelBinder 
     { 
      public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
      { 
       if (bindingContext.ModelType == typeof(SimpleModel)) 
       { 
        var simpleModel= new SimpleModel(); 
        simpleModel.Other = 1; 
        simpleModel.Value = controllerContext.HttpContext.Request.Form["Complexity"]; 

        return cm; 
       } 
       return null; 
      } 
     } 

в глобальном asax:

ModelBinders.Binders.Add(typeof (SimpleModel), new MBinder()); 

код в Вид:

@model ComplexModel 

    @using (Html.BeginForm()) 
{ 
    <fieldset> 
     @Html.LabelFor(x => x.Complexity) 
     @Html.TextBoxFor(x => x.Complexity) 
    </fieldset> 

    <fieldset> 
     @Html.LabelFor(x => x.StrVal) 
     <br /> 
     @Html.EditorFor(x => x.StrVal) 
    </fieldset> 
    <input type="submit" /> 
} 

Контроллер:

public ActionResult Index() 
     { 
      return View(); 
     } 

     [HttpPost] 
     public ActionResult Index(ComplexModel model) 
     { 
      return RedirectToAction("Index"); 

     } 

BTW в MVC 3 лучший вариант будет использовать интерфейс IModelBinderProvider, но я просто хотел показать то, что будет работать.

 Смежные вопросы

  • Нет связанных вопросов^_^