3

Я создаю несколько пользовательских связующих для сложных типов в моей модели. Моя модель состоит из объектов, которые имеют свои собственные связующие. Я хочу, чтобы базовый объект выполнял свою грязную работу, а затем заполнял сложный объект, который он инкапсулирует, передавая стандартную маршрутизацию ModelBinder. Как мне это сделать?Как вызвать UpdateModel из пользовательского ModelBinder? (MVC)

Для иллюстрации я создал очень простой пример.

Скажите, что моя модель содержит эти объекты.

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

И у меня есть следующие Связки для каждой из этих моделей. Не то, чтобы PersonBinder необходимо заполнить PhoneNumber, но не хочет дублировать код в связке PhoneNumber. Как он делегирует обратно в стандартную маршрутизацию Binder?

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

И, конечно же, я зарегистрировал свои ModelBinders в файле Global.asax.cs.

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

    RegisterRoutes(RouteTable.Routes); 

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

Спасибо,

Джастин

ответ

2

Ну, мне удалось найти решение. Пожалуйста, не стесняйтесь прокомментировать его достоверность.

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

Вот краткое изложение того, что я сделал.

  1. Взгляд вверх ModelBinder с использованием глобально доступной коллекции ModelBinders.Binders (Откат по умолчанию, если он не зарегистрирован)
  2. Создание ModelMetadataProvider для модели я связывания.
  3. Задайте свойство ModelName свойства bindingContext для свойства модели, которое я пытаюсь заполнить («PhoneNumber»).
0

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

+0

Спасибо за предложение, но я не думаю, что AutoMapper - это инструмент для меня. Это похоже на обходной путь. Я уверен, что связующие должны поддерживать эту функциональность изначально. – Justin