使用 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 代码处理该接口。这将允许从代码的其他部分隐藏这种技术依赖性。
我有以下自定义模型活页夹:
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 代码处理该接口。这将允许从代码的其他部分隐藏这种技术依赖性。