Ninject to Simple Injector: зарегистрируйте ActionFilter с атрибутом контроллера (с параметрами) - PullRequest
0 голосов
/ 18 июня 2020

У меня есть приложение WebApi, которое использует Simple Injector, и я пытаюсь настроить конкретный фильтр с атрибутом контроллера (с параметрами). У меня эта конфигурация работает в другом проекте, в котором используется 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?

1 Ответ

1 голос
/ 19 июня 2020

Пакеты интеграции Simple Injector Web API не содержат функции интеграции для фильтров действий, как пакет интеграции Ninject. Но такую ​​интеграцию можно построить в несколько строк кода.

Здесь есть несколько вариантов. Первый вариант - вернуться к разрешению служб непосредственно из вашего фильтра действий, как показано в документации . Этот подход хорош, когда у вас есть один класс фильтра, но это не самый чистый подход, и он заставит вас внести изменения в уже созданный атрибут фильтра.

Таким образом, в качестве второго варианта вы можете создать прокси-класс фильтра действий, который может перенаправить вызов вашему реальному классу фильтра, который затем может быть разрешен Simple Injector:

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 не может предоставить информацию об атрибуте (UserType[]) конструктору RequiresAtLeastOneOfUserTypesFilter. Вместо этого вы можете изменить 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)
    {
    }
}

Третий вариант, который можно использовать, - это тот, который упоминается в документации , который описан в этом блоге post , в котором обсуждается модель, в которой вы размещаете свои фильтры за абстракцией c, специфичной для приложения, и позволяете им автоматически регистрироваться. Он использует аналогичный прокси-подход. Этот метод полезен, когда у вас есть несколько / много фильтров, которые необходимо применить (где их порядок выполнения не имеет значения).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...