Ninject 到简单注入器:使用控制器属性(带参数)注册 ActionFilter
Ninject to Simple Injector: Register ActionFilter with Controller Attribute (with params)
我有一个使用 Simple Injector 的 WebApi 应用程序,我正在尝试使用控制器属性(带参数)配置特定过滤器。我在另一个使用 Ninject 的项目中使用此配置,但我不知道如何在 Simple Injector 上执行此操作。
public enum UserType {
Director,
Developer,
Leader
}
我的控制器:
[RequiresAtLeastOneOfUserTypes(UserType.Developer, UserType.Leader)]
public class MyController : Controller
{
...
}
我的属性:
public sealed class RequiresAtLeastOneOfUserTypesAttribute : Attribute
{
public UserType[] TypesToBeVerified { get; set; }
public RequiresAtLeastOneOfUserTypesAttribute(params UserType[] typesToBeVerified)
{
TypesToBeVerified = typesToBeVerified;
}
}
我的过滤器:
public class RequiresAtLeastOneOfUserTypesFilter : IActionFilter
{
private readonly IUser _user;
private readonly UserType[] _typesToBeVerified;
protected RequiresAtLeastOneOfUserTypesFilter(IUser user, params UserType[] typesToBeVerified)
{
_user = user;
_typesToBeVerified = typesToBeVerified;
}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
bool authorized = _user.HasAtLeastOneOfTypes(_typesToBeVerified);
if (!authorized)
{
throw new ForbiddenUserException();
}
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
// do nothing
}
}
最后是我的 Ninject 配置:
this.BindFilter<RequiresAtLeastOneOfUserTypesFilter>(FilterScope.Controller, 0)
.WhenControllerHas<RequiresAtLeastOneOfUserTypesAttribute>()
.WithConstructorArgumentFromControllerAttribute<RequiresAtLeastOneOfUserTypesAttribute>(
"typesToBeVerified",
attribute => attribute.typesToBeVerified);
我的问题是:如何使用 Simple Injector 进行此配置?
Simple Injector Web API 集成包不像 Ninject 的集成包那样包含操作过滤器的集成功能。但是这样的集成可以用几行代码构建。
这里有几个选项。第一个选项是恢复为直接从操作过滤器内部解析服务,如 documentation 中所示。当您只有一个过滤器 class 时,这种方法很好,但不是最干净的方法,并且会迫使您对已创建的过滤器属性进行更改。
因此,作为第二个选项,您可以创建一个操作过滤器代理 class,它能够将调用转发到您的真实过滤器 class,然后可以通过简单注入器解决:
public class ActionFilterProxy<T> : IActionFilter
where T : IActionFilter
{
public ActionFilterProxy(Container container) => _container = container;
public void OnActionExecuting(ActionExecutingContext filterContext) =>
_container.GetInstance<T>().OnActionExecuting(filterContext);
public void OnActionExecuted(ActionExecutedContext filterContext) =>
_container.GetInstance<T>().OnActionExecuted(filterContext);
}
使用此代理,您可以进行以下配置:
GlobalConfiguration.Configuration.Filters.Add(
new ActionFilterProxy<RequiresAtLeastOneOfUserTypesFilter>(container));
container.Register<RequiresAtLeastOneOfUserTypesFilter>();
这仍然迫使您对 RequiresAtLeastOneOfUserTypesFilter
进行更改,因为 Simple Injector 无法向 RequiresAtLeastOneOfUserTypesFilter
的构造函数提供属性信息(UserType[]
)。相反,您可以将 RequiresAtLeastOneOfUserTypesFilter
更改为以下内容:
public class RequiresAtLeastOneOfUserTypesFilter : IActionFilter
{
private readonly IUser _user;
public RequiresAtLeastOneOfUserTypesFilter(IUser user) => _user = user;
public void OnActionExecuting(ActionExecutingContext filterContext)
{
// Get the attribute from the controller here
var attribute = filterContext.ActionDescriptor.ControllerDescriptor
.GetCustomAttribute<RequiresAtLeastOneOfUserTypesAttribute>();
bool authorized = _user.HasAtLeastOneOfTypes(attribute.TypesToBeVerified);
if (!authorized)
{
throw new ForbiddenUserException();
}
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
}
}
要使用的第三个选项是 documentation 中提到的选项,在 这篇博客 post 中进行了描述,其中讨论了一个模型您将过滤器置于特定于应用程序的抽象之后,并允许它们自动注册。它使用类似的代理方法。当您有 multiple/many 个需要应用的过滤器(它们的执行顺序无关紧要)时,此方法很有用。
我有一个使用 Simple Injector 的 WebApi 应用程序,我正在尝试使用控制器属性(带参数)配置特定过滤器。我在另一个使用 Ninject 的项目中使用此配置,但我不知道如何在 Simple Injector 上执行此操作。
public enum UserType {
Director,
Developer,
Leader
}
我的控制器:
[RequiresAtLeastOneOfUserTypes(UserType.Developer, UserType.Leader)]
public class MyController : Controller
{
...
}
我的属性:
public sealed class RequiresAtLeastOneOfUserTypesAttribute : Attribute
{
public UserType[] TypesToBeVerified { get; set; }
public RequiresAtLeastOneOfUserTypesAttribute(params UserType[] typesToBeVerified)
{
TypesToBeVerified = typesToBeVerified;
}
}
我的过滤器:
public class RequiresAtLeastOneOfUserTypesFilter : IActionFilter
{
private readonly IUser _user;
private readonly UserType[] _typesToBeVerified;
protected RequiresAtLeastOneOfUserTypesFilter(IUser user, params UserType[] typesToBeVerified)
{
_user = user;
_typesToBeVerified = typesToBeVerified;
}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
bool authorized = _user.HasAtLeastOneOfTypes(_typesToBeVerified);
if (!authorized)
{
throw new ForbiddenUserException();
}
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
// do nothing
}
}
最后是我的 Ninject 配置:
this.BindFilter<RequiresAtLeastOneOfUserTypesFilter>(FilterScope.Controller, 0)
.WhenControllerHas<RequiresAtLeastOneOfUserTypesAttribute>()
.WithConstructorArgumentFromControllerAttribute<RequiresAtLeastOneOfUserTypesAttribute>(
"typesToBeVerified",
attribute => attribute.typesToBeVerified);
我的问题是:如何使用 Simple Injector 进行此配置?
Simple Injector Web API 集成包不像 Ninject 的集成包那样包含操作过滤器的集成功能。但是这样的集成可以用几行代码构建。
这里有几个选项。第一个选项是恢复为直接从操作过滤器内部解析服务,如 documentation 中所示。当您只有一个过滤器 class 时,这种方法很好,但不是最干净的方法,并且会迫使您对已创建的过滤器属性进行更改。
因此,作为第二个选项,您可以创建一个操作过滤器代理 class,它能够将调用转发到您的真实过滤器 class,然后可以通过简单注入器解决:
public class ActionFilterProxy<T> : IActionFilter
where T : IActionFilter
{
public ActionFilterProxy(Container container) => _container = container;
public void OnActionExecuting(ActionExecutingContext filterContext) =>
_container.GetInstance<T>().OnActionExecuting(filterContext);
public void OnActionExecuted(ActionExecutedContext filterContext) =>
_container.GetInstance<T>().OnActionExecuted(filterContext);
}
使用此代理,您可以进行以下配置:
GlobalConfiguration.Configuration.Filters.Add(
new ActionFilterProxy<RequiresAtLeastOneOfUserTypesFilter>(container));
container.Register<RequiresAtLeastOneOfUserTypesFilter>();
这仍然迫使您对 RequiresAtLeastOneOfUserTypesFilter
进行更改,因为 Simple Injector 无法向 RequiresAtLeastOneOfUserTypesFilter
的构造函数提供属性信息(UserType[]
)。相反,您可以将 RequiresAtLeastOneOfUserTypesFilter
更改为以下内容:
public class RequiresAtLeastOneOfUserTypesFilter : IActionFilter
{
private readonly IUser _user;
public RequiresAtLeastOneOfUserTypesFilter(IUser user) => _user = user;
public void OnActionExecuting(ActionExecutingContext filterContext)
{
// Get the attribute from the controller here
var attribute = filterContext.ActionDescriptor.ControllerDescriptor
.GetCustomAttribute<RequiresAtLeastOneOfUserTypesAttribute>();
bool authorized = _user.HasAtLeastOneOfTypes(attribute.TypesToBeVerified);
if (!authorized)
{
throw new ForbiddenUserException();
}
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
}
}
要使用的第三个选项是 documentation 中提到的选项,在 这篇博客 post 中进行了描述,其中讨论了一个模型您将过滤器置于特定于应用程序的抽象之后,并允许它们自动注册。它使用类似的代理方法。当您有 multiple/many 个需要应用的过滤器(它们的执行顺序无关紧要)时,此方法很有用。