找到了解决办法。不幸的是,它不像原来的那样通用 - 但它允许视图模型的模型绑定器。
我将原来的 StepViewModelBinder 替换为以下内容:
public class StepViewModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
var stepTypeValue = bindingContext.ValueProvider.GetValue("StepType");
var stepType = Type.GetType((string)stepTypeValue.ConvertTo(typeof(string)), true);
var step = Activator.CreateInstance(stepType);
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => step, stepType);
return step;
}
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
//bind using default binding, and calls the overriden "CreateModel"
var model = base.BindModel(controllerContext, bindingContext);
//if the modelstate is not valid return to controller with found error
if (!bindingContext.ModelState.IsValid)
return model;
//if the modelstate is valid, call the modelbinder for the concreteType
var ll = Binders.GetBinder(model.GetType());
return ll.BindModel(controllerContext, bindingContext);
}
}
此解决方案为模型获取关联的模型绑定器 - 缺点是,由于具体实现隐藏在接口后面,因此模型绑定器需要才能用于具体实现,因为具体类型不能从接口实例化
具体类的模型绑定器可能如下所示:
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
var step = new Step1();
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => step, step.GetType());
return step;
}
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var model = (Step1)base.BindModel(controllerContext, bindingContext);
bindingContext.ModelState.AddModelError("", "This is a test");
return model;
}
modelbinder 像往常一样与 viewmodel 耦合在一起,要么通过
ModelBinders.Binders.Add(typeof(Step1), new Step1ModelBinder());
或通过类注解:
[ModelBinder(typeof(OpretBrugerStep1ModelBinder))]
我刚刚为不需要特定实现的步骤实现创建了一个通用的默认模型绑定器 - 只是为了让它们与示例一起工作:
public class DefaultStepModelBinder<T> : DefaultModelBinder where T : IStepViewModel, new()
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
var step = new T();
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => step, step.GetType());
return step;
}
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var model = (T)base.BindModel(controllerContext, bindingContext);
return model;
}
}
因此,具体步骤可以使用此模型绑定器 - 以 step1 为例:
[ModelBinder(typeof(DefaultStepModelBinder<Step1>))]
[Serializable]
public class Step1 : IStepViewModel
{ ... }