使用 Ninject 将 Class 注入 IModelBinder

Injecting Class into IModelBinder using Ninject

我有以下自定义模型活页夹:

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); 
    }
}

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

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

您需要自定义 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 代码处理该接口。这将允许从代码的其他部分隐藏这种技术依赖性。