代码之家  ›  专栏  ›  技术社区  ›  Justin Rusbatch

使用autofac将服务注入基类

  •  2
  • Justin Rusbatch  · 技术社区  · 14 年前

    DR: 如何合并由两个自定义用户共享的逻辑 ModelBinder 当两个实现都依赖autofac向它们注入(公共)依赖关系时,实现是在单个基类中实现的吗?


    在回顾我正在开发的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;
        }
    }
    

    使用autopac,我如何注入 IEncodingService公司 在强制派生类提供要编码的属性名称时,是否将其转换为基类构造函数?

    1 回复  |  直到 14 年前
        1
  •  3
  •   Bryan Watts    14 年前

    实际上,我会用稍微不同的方式来处理这个问题, 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");
    
    推荐文章