代码之家  ›  专栏  ›  技术社区  ›  Alex

C MVC:何时使用特定(非默认)ModelBinder?

  •  1
  • Alex  · 技术社区  · 16 年前

    据我所知,默认模型绑定器能够

    <input type="text" name="myType.property1" value="John Doe" />
    <input type="text" name="myType.property2" value="22" />
    

    进入:

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult SomeAction(MyType myType)
    {
         // This will be "John Doe"
         String someName = myType.property1;
         // This will be 22
         Int32 someNumber = myType.property2;
    
    
         // 
         // irrelevant magic
    }         
    

    在什么情况下,我将使用非默认的模型绑定器?我想不出一个理由不命名HTML输入的任何不同于类属性名称。请举例说明。

    谢谢您!

    3 回复  |  直到 16 年前
        1
  •  3
  •   fretje    16 年前

    在这种情况下, MyType 例如,没有默认的构造函数(默认的ModelBinder需要一个默认的构造函数)。
    如果使用工厂方法模式创建新对象(非常简单的示例仅用于说明;-),则可能发生这种情况:

    public class MyType
    {
        private MyType() // prevent direct creation through default constructor
        {  
        }
    
        public static MyType CreateNewMyType()
        {
            return new MyType();
        }
    }
    

    然后您必须实现一个自定义的modelbinder,它调用工厂方法 CreateNewMyType() 而不是创建新的 MyType 通过反射:

    public class MyTypeBinder : DefaultModelBinder
    {
        protected override object CreateModel(ControllerContext controllerContext,
                                              ModelBindingContext bindingContext,
                                              Type modelType)
        {
            return MyType.CreateNewMyType();
        }
    }
    

    另外,如果您对默认ModelBinder的当前功能或实现不满意,那么您可以用自己的实现轻松地替换它。

        2
  •  2
  •   Robert Harvey    16 年前

    考虑一个名为TimeInterval的自定义类型,该类型存储为Double,但显示为 H.M.S.FFFFFF 其中ffffff是分数秒。使用自定义绑定,可以向绑定器演示如何正确解析和显示这些数字,而不必在控制器中编写自定义代码。

    // This class implements a custom data type for data binding.
    public class TimeInterval
    {
        double _value;
    
        public TimeInterval(string value)
        {
            // Extension method parses string value to double.
            _value = value.ToSeconds();
        }
        public TimeInterval(double value)
        {
            _value = value;
        }
        public string GetText()
        {
            // Extension method formats double value as time string.
            return _value.ToTimeString();
        }
        public double? GetValue()
        {
            return _value;
        }
    }
    
    // This class implements custom binding for the TimeInterval custom type.  
    // It is registered in Global.asax 
    public class TimeIntervalBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            string value = GetAttemptedValue(bindingContext);
    
            if (value == "")
                return null;
    
            return new TimeInterval(value);
        }
    
        private static string GetAttemptedValue(ModelBindingContext context)
        {
            ValueProviderResult value = context.ValueProvider[context.ModelName];
            return value.AttemptedValue ?? string.Empty;
        }
    }
    
    // in Global.asax:
    protected void Application_Start()
    {
        RegisterRoutes(RouteTable.Routes);
        ModelBinders.Binders.Add(typeof(TimeInterval), new TimeIntervalBinder());
    }
    

    现在,新的自定义类型将自动进行绑定。

        3
  •  2
  •   nkirkes    16 年前

    斯科特·汉塞尔曼 a simple case study for a custom model binder.

    文章的重点不是他试图做的事情不能用默认绑定的其他方式完成,而是 他在尝试 它允许他重新使用代码来完成这项工作。