2010-02-16 5 views
7

Ich habe, was ich denke, ist eine etwas normale Situation, in der ich Form-Posts an ein "Bestell" -Modell binden muss. Dieses Modell verfügt über ein paar Stufen von Informationen, um es:DefaultModelBinder Problem mit verschachtelten Ebenen + anderen Bindemitteln

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

die Default benutzen, wenn ich ein Formular auf eine Aktion POST, die dieses Auftragsmodell als param nimmt die folgenden Felder JustWork (TM):

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

Dieses Feld nicht:

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

die Falten ich mit dem Landhaus haben ist. In unserem Fall gibt Address.Country eine Country-Klasseninstanz zurück (ISO2/3/Name/Code-Logik). Es ist keine Zeichenfolge. Nicht überraschend, dass es standardmäßig nicht funktioniert.

Mein erster Gedanke war, einen CountryModelBinder (erben DefaultModelBinder) und ModelBinders.Binders.Add es zum Typ des Landes zu erstellen. Wenn ich das tue, wird CountryModelBinder nie in dem obigen Szenario aufgerufen.

Mein zweiter Gedanke war, einen AddressModelBinder (inherit DefaultModelBinder) zu erstellen und an unseren Adresstyp zu binden. Während dies aufgerufen wird, hat der Aufruf von SetProperty für "Country" einen leeren Wert, obwohl das Formular ein Feld namens "Billing.Address.Country" gebucht hat.

Nach einigem Basteln scheint es, dass das Modellbindungsverhalten CreateModel nur dann aufruft, wenn das Modell die oberste Klasse der Aktion ist und alle anderen Binder ihre BindPropery/SetProperty für untergeordnete Eigenschaften aufgerufen haben.

Mit anderen Worten, wenn ich Modellbinder für Auftrag, OrderAddress (Fakturierung), Adresse und Land erstellen. Für die Aktion, die eine Bestellung annimmt, wird nur OrderModelBinder.CreateModel aufgerufen. ORderAddress und Address.BindProperty/SetProperty werden für einige Dinge aufgerufen, und manchmal ist das SetProperty-Wertargument leer, wenn es eindeutig in einem Namen gepostet wurde, der mit den anderen Feldeigenschaftszuordnungen übereinstimmt.

Es ist einfach genug, Code zu OrderModelBinder hinzuzufügen, um Billing.Address.Country aus Request.Form zu ziehen. Aber ich habe mehrere Modelle, die Address verwenden und alle tun, was kaputt scheint.

Was fehlt mir hier? Gibt es eine Möglichkeit, dass der CountryModelBinder in diesem Fall tatsächlich aufgerufen wird? Ich würde denken, dass der CountryModelBinder aufgerufen werden sollte, wenn Billing.Address.Country der Country-Eigenschaft der Adressmappe zugeordnet ist.

+0

das könnte Ihnen helfen: http://StackOverflow.com/Questions/2462506/model-binding-with-nested-child-model-and-partialviews-in-asp-net-mvc – Will

+0

Ich habe das gleiche Problem Bei einer geschachtelten Modellstruktur scheint es, dass Eigenschaften auf der obersten Ebene und eine Ebene nach unten gebunden werden, aber alles, was darunter liegt, scheint ignoriert zu werden. Ist das das normale Verhalten des Modellbinders? Scheint eher willkürliches Verhalten. – UpTheCreek

Antwort

0

Ich habe versucht, was Sie hier getan haben, anscheinend auf MVC3 funktioniert es tatsächlich, wenn ich einen Modellbinder für diesen Typ zur Verfügung stellen.

Dies ist nur ein Proof of Concept zu zeigen, dass es funktioniert, und nicht wie einmal in der Nähe der Produktion Level-Code sollte gesehen:

Modelle:

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

einige Bindemittel:

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

in globaler asax:

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

Code in Aussicht:

@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" /> 
} 

Controller:

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

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

     } 

BTW in MVC 3 eine bessere Option wäre, die IModelBinderProvider Schnittstelle zu verwenden, aber ich wollte nur etwas zeigen, die funktionieren würde.

Verwandte Themen