实际上,我会用稍微不同的方式来处理这个问题,
favoring composition over inheritance
. 这意味着我将封装属性操作的细节,并将不同的实现传递给单个模型绑定器。
首先,定义一个表示绑定单个属性的接口:
public interface IPropertyBinder
{
void SetPropertyValue(object model, ModelBindingContext context);
}
然后,使用最初来自的参数实现它
EncodedPropertyModelBinder
:
public sealed class PropertyBinder : IPropertyBinder
{
private readonly IEncodingService _encodingService;
private readonly string _propertyName;
public PropertyBinder(IEncodingService encodingService, string propertyName)
{
_encodingService = encodingService;
_propertyName = propertyName;
}
public void SetPropertyValue(object model, ModelBindingContext bindingContext)
{
var value = bindingContext.ValueProvider.GetValue(_propertyName);
if(value != null && !value.AttemptedValue.IsNullOrEmpty())
{
var encodedValue = _encodingService.Encode(value.AttemptedValue);
var property = model.GetType().GetProperty(_propertyName);
property.SetValue(model, encodedValue, null);
}
}
}
下一步,实施
编码属性模型绑定器
使用新界面:
public class EncodedPropertyModelBinder : DefaultModelBinder
{
private readonly IPropertyBinder _propertyBinder;
public EncodedPropertyModelBinder(IPropertyBinder propertyBinder)
{
_propertyBinder = propertyBinder;
}
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var model = base.BindModel(controllerContext, bindingContext);
if(model != null)
{
_propertyBinder.SetPropertyValue(model, bindingContext);
}
return model;
}
}
最后,使用autopac命名实例注册视图模型的两个版本,传递
PropertyBinder
:
builder.
Register(c => new EncodedPropertyModelBinder(new PropertyBinder(c.Resolve<IEncodingService>(), "Answer")))
.Named<EncodedPropertyModelBinder>("AnswerBinder");
builder.
Register(c => new EncodedPropertyModelBinder(new PropertyBinder(c.Resolve<IEncodingService>(), "SecretKey")))
.Named<EncodedPropertyModelBinder>("SecretKeyBinder");