【问题标题】:How do I invoke UpdateModel from within a Custom ModelBinder? (MVC)如何从自定义 ModelBinder 中调用 UpdateModel? (MVC)
【发布时间】:2010-07-07 04:37:04
【问题描述】:

我正在为我的模型中的复杂类型创建一些自定义绑定器。我的模型由具有自己单独的活页夹的对象组成。我希望基础对象完成其肮脏的工作,然后通过传递给标准 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;}
}

对于每个模型,我都有以下 Binder。并不是说 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;
    }
}

当然,我已经在 Global.asax.cs 文件中注册了我的 ModelBinders。

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

    RegisterRoutes(RouteTable.Routes);

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

谢谢,

贾斯汀

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-2 modelbinders custom-model-binder imodelbinder


    【解决方案1】:

    好吧,我设法想出了一个解决方案。请随时评论其有效性。

    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. 使用全局可访问的 ModelBinders.Binders 集合查找 ModelBinder(如果未注册则回退到默认值)
    2. 为我要绑定的模型创建 ModelMetadataProvider。
    3. 将 bindingContext 的 ModelName 属性设置为我要填充的模型属性(“PhoneNumber”)。

    【讨论】:

      【解决方案2】:

      您可以使用 AutoMapper 并在 Action 中处理复杂的模型构造,而不是编写活页夹。

      【讨论】:

      • 感谢您的建议,但我认为 AutoMapper 不是适合我的工具。似乎是一种解决方法。我确信活页夹应该原生支持这个功能。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-28
      • 1970-01-01
      • 1970-01-01
      • 2018-06-26
      • 2018-01-24
      • 1970-01-01
      • 2012-01-10
      相关资源
      最近更新 更多