Подтвердить что ты не робот

Вставить услугу в Action Filter

Я пытаюсь внедрить службу в свой фильтр действий, но я не получаю требуемую службу, вложенную в конструктор. Вот что я имею:

public class EnsureUserLoggedIn : ActionFilterAttribute
{
    private readonly ISessionService _sessionService;

    public EnsureUserLoggedIn()
    {
        // I was unable able to remove the default ctor 
        // because of compilation error while using the 
        // attribute in my controller
    }

    public EnsureUserLoggedIn(ISessionService sessionService)
    {
        _sessionService = sessionService;
    }

    public override void OnActionExecuting(ActionExecutingContext context)
    {
        // Problem: _sessionService is null here
        if (_sessionService.LoggedInUser == null)
        {
            context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
            context.Result = new JsonResult("Unauthorized");
        }
    }
}

И я украшаю свой контроллер следующим образом:

[Route("api/issues"), EnsureUserLoggedIn]
public class IssueController : Controller
{
}

Startup.cs

services.AddScoped<ISessionService, SessionService>();
4b9b3361

Ответ 1

Используя эти статьи в качестве ссылки:

Основные фильтры действий ASP.NET

Фильтры действий, служебные фильтры и фильтры типов в ASP.NET 5 и MVC 6

Использование фильтра в качестве ServiceFilter

Поскольку фильтр будет использоваться как ServiceType, его необходимо зарегистрировать в IoC платформы. Если бы фильтры действий использовались напрямую, это не потребовалось бы.

Startup.cs

public void ConfigureServices(IServiceCollection services) {
    services.AddMvc();

    services.AddScoped<ISessionService, SessionService>();
    services.AddScoped<EnsureUserLoggedIn>();

    ...
}

Пользовательские фильтры добавляются в метод контроллера MVC и класс контроллера с ServiceFilter атрибута ServiceFilter например:

[ServiceFilter(typeof(EnsureUserLoggedIn))]
[Route("api/issues")]
public class IssueController : Controller {
    // GET: api/issues
    [HttpGet]
    [ServiceFilter(typeof(EnsureUserLoggedIn))]
    public IEnumerable<string> Get(){...}
}

Были и другие примеры

  • Использование фильтра в качестве глобального фильтра

  • Использование фильтра с базовыми контроллерами

  • Использование фильтра с заказом

Посмотрите, попробуйте и посмотрите, решит ли это вашу проблему.

Надеюсь это поможет.

Ответ 2

Глобальные фильтры

Вам нужно реализовать IFilterFactory:

public class AuthorizationFilterFactory : IFilterFactory
{
    public bool IsReusable => false;

    public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
    {
        // manually find and inject necessary dependencies.
        var context = (IMyContext)serviceProvider.GetService(typeof(IMyContext));
        return new AuthorizationFilter(context);
    }
}

В классе Startup вместо регистрации фактического фильтра вы регистрируете свой фильтр factory:

services.AddMvc(options =>
{
    options.Filters.Add(new AuthorizationFilterFactory());
});

Ответ 3

Еще один способ решения этой проблемы. Вы можете получить свое обслуживание через Контекст, как в следующем коде:

public override void OnActionExecuting(ActionExecutingContext context)
{
    _sessionService = context.HttpContext.RequestServices.GetService<ISessionService>();
    if (_sessionService.LoggedInUser == null)
    {
        context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
        context.Result = new JsonResult("Unauthorized");
    }
}

Обратите внимание, что вам необходимо зарегистрировать эту службу в Startup.cs

services.AddTransient<ISessionService, SessionService>();

Ответ 4

После прочтения этой статьи ASP.NET Core - Реальные фильтры ASP.NET Core MVC (август 2016 г.) я реализовал это так:

В Starup.cs/ConfigureServices:

services.AddScoped<MyService>();

В MyFilterAttribute.cs:

public class MyFilterAttribute : TypeFilterAttribute
{        
    public MyFilterAttribute() : base(typeof (MyFilterAttributeImpl))
    {

    }

    private class MyFilterAttributeImpl : IActionFilter
    {
        private readonly MyService _sv;

        public MyFilterAttributeImpl(MyService sv)
        {
            _sv = sv;
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {                
            _sv.MyServiceMethod1();
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            _sv.MyServiceMethod2();
        }
    }
}

В MyFooController.cs:

[MyFilter]
public IActionResult MyAction()
{
}

Изменение: Передача аргументов, таких как [MyFilter("Something")] может быть сделано с помощью свойства Arguments класса TypeFilterAttribute: Как добавить параметр в фильтр действий в asp.net? (код rboe также показывает, как вводить вещи (таким же образом))

Ответ 5

пример

private ILoginService _loginService;

public override void OnActionExecuting(ActionExecutingContext context)
        {
            _loginService = (ILoginService)context.HttpContext.RequestServices.GetService(typeof(ILoginService));
        }

Надеюсь, поможет.

Ответ 6

Хотя вопрос неявно относится к "фильтрам по атрибутам", все же стоит подчеркнуть, что добавление фильтров "глобально по типу" поддерживает DI "из коробки":

[Для глобальных фильтров, добавляемых по типу] любые зависимости конструктора будут заполняться путем внедрения зависимостей (DI). Добавление фильтра по типу эквивалентно filters.Add(new TypeFilterAttribute (typeof (MyFilter))). https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-2.2#dependency-injection

Что касается атрибутных фильтров:

Фильтры, которые реализованы в виде атрибутов и добавлены непосредственно в классы контроллера или методы действия, не могут иметь конструкторских зависимостей, обеспечиваемых внедрением зависимостей (DI). Это потому, что атрибуты должны иметь свои параметры конструктора, где они применяются. Это ограничение работы атрибутов. https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-2.2#dependency-injection

Однако, как упоминалось в предыдущих ответах на ФП, существуют способы косвенного обращения, которые можно использовать для достижения DI. Для полноты, вот ссылки на официальные документы: