2010-02-16 19 views
7

Tengo lo que creo que es una situación algo normal en la que necesito vincular publicaciones a un modelo de "orden". Este modelo tiene unos niveles de información a la misma:DefaultModelBinder Problema con niveles anidados + otros enlazadores

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

Utilizando el DefaultModelBinder, si puedo enviar un formulario para una acción que lleva este modelo de orden que el parámetro, los siguientes campos JustWork (TM):

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

Este campo no es así:

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

el arrugas que tengo es con la hacienda. En nuestro caso, Address.Country devuelve una instancia de clase Country (ISO2/3/Name/Code logic). No es una cadena. No es de extrañar que no funcione por defecto.

Mi primer pensamiento fue crear un CountryModelBinder (heredar DefaultModelBinder) y ModelBinders.Binders.Add al tipo de país. Cuando hago eso, CountryModelBinder nunca se llama en el escenario anterior.

Mi segundo pensamiento fue crear un AddressModelBinder (heredar DefaultModelBinder) y vincularlo a nuestro tipo de dirección. Mientras se llama, la llamada SetProperty para "País" tiene un valor vacío, aunque el formulario haya publicado un campo llamado "Billing.Address.Country".

Después de algunas modificaciones, parece que el comportamiento de vinculación del modelo solo llama a CreateModel cuando el modelo es de la clase de nivel superior que desea la acción, y todas las demás carpetas tienen sus propiedades secundarias BindPropery/SetProperty.

En otras palabras, si creo carpetas modelo para Order, OrderAddress (Billing), Address y Country. Para la acción que toma una orden, solo se llama a OrderModelBinder.CreateModel. Se llama a ORderAddress y Address.BindProperty/SetProperty para algunas cosas, y algunas veces el argumento de valor de SetProperty está vacío cuando se publicó claramente en un nombre que coincide con las otras asignaciones de propiedades de campo.

Es bastante fácil simplemente agregar código a OrderModelBinder para sacar a Billing.Address.Country de Request.Form. Pero tengo varios modelos que usan Address y tener todos ellos que parece roto.

¿Qué me falta aquí? ¿Hay alguna manera de que se llame realmente a CountryModelBinder en este caso? Creo que debería llamarse a CountryModelBinder cuando se mapea Billing.Address.Country en la propiedad Country del archivador Address.

+0

esto podría ayudarlo: http://stackoverflow.com/questions/2462506/model-binding-with-nested-child-models-and-partialviews-in-asp-net-mvc – Will

+0

Tengo el mismo problema con una estructura de modelo anidado, me parece que las propiedades en el nivel superior, y un nivel hacia abajo, están siendo atadas, pero cualquier cosa más baja que eso parece ser ignorada. ¿Es este el comportamiento normal de la carpeta modelo? Parece un comportamiento bastante arbitrario. – UpTheCreek

Respuesta

0

He intentado hacer lo que ha hecho aquí, aparentemente en MVC3, de hecho funciona si proporciono un modelo de encuadernación para ese tipo.

Esto es sólo una prueba de concepto para demostrar que funciona, y no debe ser visto como incluso cerca de código de nivel de producción:

Modelos:

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

algunos ligante:

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

en GLOBAL.ASAX:

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

código en la vista:

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

controlador:

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

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

     } 

Por cierto, en MVC 3 una mejor opción sería utilizar la interfaz IModelBinderProvider, pero yo sólo quería mostrar algo que funcione.

Cuestiones relacionadas