Как вызвать UpdateModel из пользовательского ModelBinder?(MVC) - PullRequest
3 голосов
/ 06 июля 2010

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

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

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

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

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

Джастин

Ответы [ 2 ]

2 голосов
/ 07 июля 2010

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

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 голосов
/ 06 июля 2010

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

...