MVC:是否可以在一个模型上拥有一个自定义ModelBinder和默认绑定器?

时间:2011-09-22 22:52:55

标签: asp.net-mvc-3 modelbinder

我想使用我的自定义绑定器来处理构造函数(必要),然后让默认的模型绑定器正常填写其余的属性。

编辑:自定义的一个当然会先运行。

3 个答案:

答案 0 :(得分:1)

莫的回答是正确的。从DefaultModelBinder继承然后覆盖CreateModel。 我只是发帖提供示例代码。

活页夹:

public class RegistrationViewModelBinder : DefaultModelBinder 
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        return new RegistrationViewModel(Guid.NewGuid());
    }
}

模特:

public class RegistrationViewModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }    
    public Guid Id { get; private set; }

    public RegistrationViewModel(Guid id)
    {
        Id = id;
    }
}

如果您的财产可以设置(在这种情况下是Id),您需要将其从绑定中排除:

[Bind(Exclude = "Id")]
public class RegistrationViewModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }

    public Guid Id { get; set; }
}

答案 1 :(得分:1)

谢谢大家,我想我找到了一个解决方案,那就是覆盖defaultmodelbinder的createmodel方法。我从这里得到了额外的帮助: http://noahblu.wordpress.com/2009/06/15/modelbinder-for-objects-without-default-constructors/

由于在mvc中进行了更改,因此需要更新以使用modelmetadata而不是设置该链接中显示的模型类型。 这是我最初的第一次试用,似乎有效:

namespace NorthwindMVCApp.CustomBinders{

   public class NewShipperBinder<T> : DefaultModelBinder
{

    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        Type type1 = typeof(T);
        ConstructorInfo[] constructors = type1.GetConstructors();
        ConstructorInfo largestConstructor = constructors.OrderByDescending(x => x.GetParameters().Count()).First();
        ParameterInfo[] parameters = largestConstructor.GetParameters();
        List<object> paramValues = new List<object>();
        IModelBinder binder;
        string oldModelName = bindingContext.ModelName;
        foreach (ParameterInfo param in parameters)
        {
            string name = CreateSubPropertyName(oldModelName, param.Name);
            //bindingContext.ModelType = param.ParameterType;
            bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, param.ParameterType);
            bindingContext.ModelName = name;
            if (!System.Web.Mvc.ModelBinders.Binders.TryGetValue(param.ParameterType, out binder))
                binder = System.Web.Mvc.ModelBinders.Binders.DefaultBinder;
            object model = binder.BindModel(controllerContext, bindingContext);
            paramValues.Add(model);
        }
       // bindingContext.ModelType = typeof(T);
        bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(T));
        bindingContext.ModelName = oldModelName;
        Debug.WriteLine(Environment.StackTrace); 
        object obj = Activator.CreateInstance(type1, paramValues.ToArray());
        return obj;
    }
}

}

受约束的类如下。所有这一切的原因是它没有默认构造函数(为了确保不存在非空格):

namespace Core.Entities{

[EntityAttribute()]
public class Shipper 
{

    protected Shipper() : this("Undefined")
    {

    }

    public Shipper(string CompanyName)
    {
        this.CompanyName = CompanyName;
        Orders = new List<Order>();
    }

    public virtual int ShipperID { get; set; }
    public virtual IList<Order> Orders { get; set; }
    public virtual string CompanyName { get; set; }
    public virtual string Phone { get; set; }

    public override bool Equals(object obj)
    {
        Shipper obj_Shipper;
        obj_Shipper = obj as Shipper;
        if (obj_Shipper == null)
        {
            return false;
        }
        if (obj_Shipper.CompanyName != this.CompanyName)
        {
            return false;
        }
        return true;
    }

    public override int GetHashCode()
    {
        return CompanyName.GetHashCode();
    }
}
}

顺便说一句,binder如下所示包含在global.asax中:

            ModelBinders.Binders.Add(typeof(Shipper), new CustomBinders.NewShipperBinder<Shipper>());

因此我很容易添加大量的实体类(循环),因为我维护了一系列实体类型。

因此,我已经能够将该实体更新到数据库。

编辑:有点结冰,这是一个堆栈跟踪:

at NorthwindMVCApp.CustomBinders.NewShipperBinder`1.CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) in C:\Users\####\Documents\Visual Studio 2010\Projects\TestFluentNHibernate\NorthwindMVC\NorthwindMVCApp\CustomBinders\NewShipperBinder.cs:line 37
   at System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
   at System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
   at System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)

答案 2 :(得分:0)

您是否已从DefaultModelBinder继承?我认为不可能按照您的意图行事 - 如果您创建客户模型绑定器并且它实现了IModelBinder,则该类必须执行所有必要的操作。