【问题标题】:Injecting Class into IModelBinder using Ninject使用 Ninject 将类注入 IModelBinder
【发布时间】:2019-08-16 11:14:11
【问题描述】:

我有以下自定义模型绑定器:

public class AllowAndSanitizeHtmlBinder : IModelBinder
{
    // initialize HtmlSanitizer (I want this to be injected)
    private HtmlSanitizer _htmlSanitizer = new HtmlSanitizer();
    sanitizer.PostProcessNode += (s, e) =>  
        (e.Node as IHtmlAnchorElement)?.SetAttribute("rel", "nofollow");

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var request = controllerContext.HttpContext.Request;
        var name = bindingContext.ModelName;

        // get the unvalidated user input
        var unsanitizedMessageHtmlString = request.Unvalidated[name]; 

        // removed script or any XSS threat from user input
        return _htmlSanitizer.Sanitize(unsanitizedMessageHtmlString); 
    }
}

这段代码的问题是我正在模型绑定器类中对HtmlSanitizer 进行所有初始化(这违反了 SRP)。是否可以将HtmlSanitizer 注入上述活页夹?我正在使用 Ninject。

我见过this question:接受的答案表明模型绑定器不应该依赖于任何服务,我不确定这里是否是这种情况...我认为 DI 会简化我的代码。

【问题讨论】:

    标签: asp.net-mvc dependency-injection ninject modelbinders


    【解决方案1】:

    您需要一个自定义的IModelBinderProvider 来实现这一点。

    public class AllowAndSanitizeHtmlBinderProvider : IModelBinderProvider
    {
            public HtmlSanitizer Sanitizer{get;}
    
            public AllowAndSanitizeHtmlBinderProvider(HtmlSanitizer sanitizer)
            {
              Sanitizer = sanitizer;
            }
    
            public IModelBinder GetBinder(Type modelType)
            {
                if(modelType==typeof(string)) // I assume it's string
                    return new AllowAndSanitizeHtmlBinder (Sanitizer);
                return null;
            }
    }
    
    public class AllowAndSanitizeHtmlBinder : IModelBinder
    {
        private HtmlSanitizer _htmlSanitizer;
    
        public AllowAndSanitizeHtmlBinder(HtmlSanitizer sanitizer)
        {
          _htmlSanitizer = sanitizer;
        }
    
    
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var request = controllerContext.HttpContext.Request;
            var name = bindingContext.ModelName;
    
            // get the unvalidated user input
            var unsanitizedMessageHtmlString = request.Unvalidated[name]; 
    
            // removed script or any XSS threat from user input
            return _htmlSanitizer.Sanitize(unsanitizedMessageHtmlString); 
        }
    }
    

    然后在你的 Ninject 配置中

    kernel.Bind<IModelBinderProvider>().To<AllowAndSanitizeHtmlBinderProvider >();
    kernel.Bind<HtmlSanitizer>().ToMethod(ctx => { 
        var sanitizer = new HtmlSanitizer();
        sanitizer.PostProcessNode += (s, e) =>  
            (e.Node as IHtmlAnchorElement)?.SetAttribute("rel", "nofollow");
        return sanitizer;
    });
    

    更好的方法是为AllowAndSanitizeHtmlBinder 定义一个工厂,该工厂将保持对HtmlSanitizer 的依赖。然后,提供者将只接收工厂作为依赖项。这会将HtmlSanitizer 的依赖关系掩盖给提供者。

    此外,它还允许将 HtmlSanitizer 隐藏在接口后面,并让您的所有非 Ninject 代码处理该接口。这将允许从代码的其他部分隐藏这种技术依赖关系。

    【讨论】:

    • 这是一个非常好的答案。我很欣赏你的方法。我完全忘记了模型绑定器提供者。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-28
    • 1970-01-01
    • 2012-04-29
    • 1970-01-01
    相关资源
    最近更新 更多