我想将控制器操作与系统的其他元素完全隔离,因为它是遗留代码的重构,因此可以在系统的各个位置呈现操作。为了隔离局部视图模型中属性名称的任何重叠,我希望在表单名称属性前加上一定的值,并使用BindAttribute来指示ModelBinder将模型属性与适当的前缀表单字段。
由于我有一些使用这个模型的动作,我希望我可以将[Bind]装饰器直接放在模型类本身上,避免必须装饰进入每个动作的每个模型参数。但是,这种方法似乎没有注册到绑定器,所以我最终得到了无人居住的属性。另一方面,如果我将装饰器移动到参数,一切都很好。
BindAttribute的文档表明它可以在课程中使用。这不是受支持的情况吗?
答案 0 :(得分:5)
您可以为相应的视图模型编写自定义模型绑定器:
public class MyViewModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
bindingContext.ModelName = "some_prefix";
return base.BindModel(controllerContext, bindingContext);
}
}
您可以在Application_Start
中注册并与您的视图模型关联:
ModelBinders.Binders.Add(typeof(MyViewModel), new MyViewModelBinder());
在这个例子中,我已经硬编码了前缀,但你可以使模型绑定器更通用和可重用,并考虑可用于装饰视图模型的BindAttribute
:
public class MyViewModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
// TODO: cache the result of this LINQ query to
// avoid using reflecting on each request. After all
// the metadata of the view model won't change at runtime
var bindAttribute = bindingContext
.ModelType
.GetCustomAttributes(typeof(BindAttribute), true)
.OfType<BindAttribute>()
.FirstOrDefault();
bindingContext.ModelName = bindAttribute != null ? bindAttribute.Prefix : null;
return base.BindModel(controllerContext, bindingContext);
}
}
然后剩下的就是使用Bind属性装饰您的视图模型:
[Bind(Prefix = "some_prefix")]
public class MyViewModel
{
public string Foo { get; set; }
public string Bar { get; set; }
}
并请求采用此视图模型的操作:
/someaction?some_prefix.foo=the_foo_value&some_prefix.bar=the_bar_value