Pregunta

Estoy creando un par de carpetas de encargo para los tipos complejos en mi modelo. Mi modelo se compone de objetos que tienen sus propias carpetas separadas. Quiero que el objeto base para hacer su trabajo sucio y luego rellenar el objeto complejo que encapsula haciendo pasar al encaminamiento ModelBinder estándar. ¿Cómo puedo hacer esto?

Con fines ilustrativos He creado un ejemplo muy sencillo.

Di mi modelo contiene estos objetos.

public class Person
{
    public string Name {get; set;}
    public PhoneNumber PhoneNumber {get; set;}
}

public class PhoneNumber
{
    public string AreaCode {get; set;}
    public string LocalNumber {get; set;}
}

y tengo las siguientes carpetas para cada uno de estos modelos. No es que el PersonBinder necesita para poblar el Fax, pero no quiere duplicar el código en el aglutinante de Fax. ¿Cómo delegar hacia atrás para el stardard Carpeta de enrutamiento?

public class PersonBinder: IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext     bindingContext)
    {
        Person person = new Person();
        person.Name = bindingContext.ValueProvider.GetValue(String.Format("{0}.{1}", bindingContext.ModelName, "Name")).AttemptedValue

        // This is where I'd like to have the PhoneNumber object use binding from another customer ModelBinder.
        // Of course the bindingContext.ModelName should be updated to its current value + "PhoneNumber"
        person.PhoneNumber = ???;  // I don't want to explicitly call the PhoneNumberBinder it should go through standard Binding routing.  (ie.  ModelBinders.Binders[typeof(PhoneNumber)] = new PhoneNumberBinder();)

        return person;       
    }
}

public class PhoneNumberBinder: IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext     bindingContext)
    {
        PhoneNumber phoneNumber = new PhoneNumber();
        phoneNumber.AreaCode = bindingContext.ValueProvider.GetValue(String.Format("{0}.{1}", bindingContext.ModelName, "AreaCode")).AttemptedValue
        phoneNumber.LocalNumber = bindingContext.ValueProvider.GetValue(String.Format("{0}.{1}", bindingContext.ModelName, "LocalNumber")).AttemptedValue

        return phoneNumber;
    }
}

Y por supuesto que he registrado mi ModelBinders en el archivo Global.asax.cs.

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    RegisterRoutes(RouteTable.Routes);

    ModelBinders.Binders[typeof(Person)] = new PersonBinder();
    ModelBinders.Binders[typeof(PhoneNumber)] = new PhoneNumberBinder();
}

Gracias,

Justin

¿Fue útil?

Solución

Bueno, yo arreglé para llegar a una solución. Siéntase libre de comentar sobre su validez.

public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
     Person person = new Person();
     person.Name = bindingContext.ValueProvider.GetValue("Name").AttemptedValue

     if (bindingContext.ModelName == String.Empty)
     {
         bindingContext.ModelName = "PhoneNumber";
     }
     else
     {
         bindingContext.ModelName = bindingContext.ModelName + ".PhoneNumber";
     }

     PhoneNumber phoneNumber = new PhoneNumber();
     bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => phoneNumber, phoneNumber.GetType());

     IModelBinder binder = ModelBinders.Binders[typeof(PhoneNumber)];
     if (binder == null)
     {
          binder = ModelBinders.Binders.DefaultBinder;
     }

     person.PhoneNumber = binder.BindModel(controllerContext, bindingContext) as PhoneNumber;

     return person;                         
}

A continuación se presenta un resumen de lo que he hecho.

  1. Búsqueda de la ModelBinder utilizando la colección ModelBinders.Binders accesible a nivel mundial (reserva para el valor por defecto si no se registra)
  2. Crear el ModelMetadataProvider para el modelo que estoy unión a.
  3. Establecer la propiedad ModelName del BindingContext a la propiedad de modelo que estoy tratando de poblar ( "Fax").

Otros consejos

En lugar de escribir un aglomerante que podía usuario AutoMapper y manejar la construcción de modelos complejos en la Acción.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top