Ninject to Simple Injector:使用控制器属性注册 ActionFilter(带参数)



我有一个使用简单注入器的 WebApi 应用程序,我正在尝试使用控制器属性(带参数(配置特定的过滤器。我在另一个使用 Ninject 的项目中使用此配置,但我不知道如何在简单注射器上执行此操作。

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 Web API 集成包不像 Ninject 的集成包那样包含操作筛选器的集成功能。但是这种集成可以在几行代码中构建。

这里有几个选项。第一个选项是恢复为直接从操作筛选器内部解析服务,如文档中所示。当您具有单个筛选器类时,此方法很好,但不是最干净的方法,并且会强制您对已创建的筛选器属性进行更改。

因此,作为第二个选项,您可以创建一个操作筛选器代理类,该代理类能够将调用转发到实际筛选器类,这可以通过简单注入器解析:

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进行更改,因为简单注入器不能向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)
{
}
}

要使用的第三个选项是文档中提到的选项,这篇博文对此进行了介绍,该文章讨论了一个模型,在该模型中,您将筛选器放在特定于应用程序的抽象后面,并允许自动注册它们。它使用类似的代理方法。当您有多个/多个筛选器需要应用(它们的执行顺序无关紧要(时,此方法很有用。

最新更新