使用 Autofac 将服务注入基类
TL;DR:当两个自定义 ModelBinder
实现都依赖 Autofac 向其中注入(公共)依赖项时,如何将两个自定义 ModelBinder
实现共享的逻辑合并到单个基类中?
在查看我正在处理的 ASP.NET MVC 项目中的一些代码时,我意识到我有两个自定义模型绑定程序,它们本质上执行相同的操作。它们都继承自 DefaultModelBinder
,并且都使用注入到其构造函数中的 IEncodingService
对两个单独的视图模型类上的单个属性进行编码。
public class ResetQuestionAndAnswerViewModelBinder : DefaultModelBinder {
public ResetQuestionAndAnswerViewModelBinder(IEncodingService encodingService) {
encoder = encodingService;
}
private readonly IEncodingService encoder;
public override object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext) {
var model = base.BindModel(controllerContext, bindingContext) as ResetQuestionAndAnswerViewModel;
if (model != null) {
var answer = bindingContext.ValueProvider.GetValue("Answer");
if ((answer != null) && !(answer.AttemptedValue.IsNullOrEmpty())) {
model.Answer = encoder.Encode(answer.AttemptedValue);
}
}
return model;
}
}
public class ConfirmIdentityViewModelBinder : DefaultModelBinder {
public ConfirmIdentityViewModelBinder(IEncodingService encodingService) {
encoder = encodingService;
}
private readonly IEncodingService encoder;
public override object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext) {
var model = base.BindModel(controllerContext, bindingContext) as ConfirmIdentityViewModel;
if (model != null) {
var secretKey = bindingContext.ValueProvider.GetValue("SecretKey");
if ((secretKey != null) && !(secretKey.AttemptedValue.IsNullOrEmpty())) {
model.SecretKeyHash = encoder.Encode(secretKey.AttemptedValue);
}
}
return model;
}
}
我为这两个类编写了一个通用基类来继承:
public class EncodedPropertyModelBinder<TViewModel> : DefaultModelBinder
where TViewModel : class {
public EncodedPropertyModelBinder(IEncodingService encodingService,
string propertyName) {
encoder = encodingService;
property = propertyName;
}
private readonly IEncodingService encoder;
private readonly string property;
public override object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext) {
var model = base.BindModel(controllerContext, bindingContext) as TViewModel;
if (model != null) {
var value = bindingContext.ValueProvider.GetValue(property);
if ((value != null) && !(value.AttemptedValue.IsNullOrEmpty())) {
var encodedValue = encoder.Encode(value.AttemptedValue);
var propertyInfo = model.GetType().GetProperty(property);
propertyInfo.SetValue(model, encodedValue, null);
}
}
return model;
}
}
使用 Autofac,我如何将 IEncodingService
注入基类构造函数,同时强制派生类提供要编码的属性名称?
TL;DR: How can I consolidate logic shared by two custom ModelBinder
implementations into a single base class, when both implementations rely on Autofac to inject a (common) dependency into them?
While reviewing some code in an ASP.NET MVC project I'm working on, I realized that I have two custom model binders that essentially do they same thing. They both inherit from DefaultModelBinder
, and they both encode a single property on two separate view model classes, using an IEncodingService
that is injected into their constructors.
public class ResetQuestionAndAnswerViewModelBinder : DefaultModelBinder {
public ResetQuestionAndAnswerViewModelBinder(IEncodingService encodingService) {
encoder = encodingService;
}
private readonly IEncodingService encoder;
public override object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext) {
var model = base.BindModel(controllerContext, bindingContext) as ResetQuestionAndAnswerViewModel;
if (model != null) {
var answer = bindingContext.ValueProvider.GetValue("Answer");
if ((answer != null) && !(answer.AttemptedValue.IsNullOrEmpty())) {
model.Answer = encoder.Encode(answer.AttemptedValue);
}
}
return model;
}
}
public class ConfirmIdentityViewModelBinder : DefaultModelBinder {
public ConfirmIdentityViewModelBinder(IEncodingService encodingService) {
encoder = encodingService;
}
private readonly IEncodingService encoder;
public override object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext) {
var model = base.BindModel(controllerContext, bindingContext) as ConfirmIdentityViewModel;
if (model != null) {
var secretKey = bindingContext.ValueProvider.GetValue("SecretKey");
if ((secretKey != null) && !(secretKey.AttemptedValue.IsNullOrEmpty())) {
model.SecretKeyHash = encoder.Encode(secretKey.AttemptedValue);
}
}
return model;
}
}
I wrote a generic base class for both of these classes to inherit from:
public class EncodedPropertyModelBinder<TViewModel> : DefaultModelBinder
where TViewModel : class {
public EncodedPropertyModelBinder(IEncodingService encodingService,
string propertyName) {
encoder = encodingService;
property = propertyName;
}
private readonly IEncodingService encoder;
private readonly string property;
public override object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext) {
var model = base.BindModel(controllerContext, bindingContext) as TViewModel;
if (model != null) {
var value = bindingContext.ValueProvider.GetValue(property);
if ((value != null) && !(value.AttemptedValue.IsNullOrEmpty())) {
var encodedValue = encoder.Encode(value.AttemptedValue);
var propertyInfo = model.GetType().GetProperty(property);
propertyInfo.SetValue(model, encodedValue, null);
}
}
return model;
}
}
Using Autofac, how would I inject the IEncodingService
into the base class constructor, while forcing derived classes to provide the name of the property to encode?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
实际上,我的处理方法略有不同,倾向于组合而不是继承。这意味着我将封装属性操作的细节,并将不同的实现传递给单个模型绑定器。
首先,定义一个表示绑定单个属性的接口:
然后,使用来自
EncodedPropertyModelBinder
的参数实现它:接下来,使用新接口实现
EncodedPropertyModelBinder
:最后,注册两个使用 Autofac 命名实例的视图模型版本,传入
PropertyBinder
的不同配置:I would actually approach this slightly differently, by favoring composition over inheritance. This means I would encapsulate the details of the property manipulation, and pass different implementations to a single model binder.
First, define an interface which represents binding a single property:
Then, implement it using the parameters originally from
EncodedPropertyModelBinder
:Next, implement
EncodedPropertyModelBinder
using the new interface:Finally, register two versions of the view model using Autofac named instances, passing in different configurations of
PropertyBinder
: