Инъекция зависимостей в пользовательский атрибут фильтра действий Web API с помощью Autofac

Я пытаюсь разрешить зависимости моего пользовательского AuthorizeAttribute который я использую для украшения моих контроллеров API в приложении MVC4. Проблема в том, что я продолжаю получать NullReferenceException о зависимости службы, которую я использую в своем пользовательском фильтре. Вот моя конфигурация Autofac:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        var builder = new ContainerBuilder();
        builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
        builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerApiRequest();
        builder.RegisterType<DatabaseFactory>().As<IDatabaseFactory>().InstancePerApiRequest();
        builder.RegisterAssemblyTypes(typeof(UserProfileRepository).Assembly)
            .Where(t => t.Name.EndsWith("Repository"))
            .AsImplementedInterfaces().InstancePerApiRequest();

        builder.RegisterAssemblyTypes(typeof(IUserProfileMapper).Assembly)
            .Where(t => t.Name.EndsWith("Mapper"))
            .AsImplementedInterfaces().InstancePerApiRequest();

        builder.RegisterAssemblyTypes(typeof(UserProfileSvc).Assembly)
            .Where(t => t.Name.EndsWith("Svc"))
            .AsImplementedInterfaces().InstancePerApiRequest();

        builder.RegisterWebApiFilterProvider(config);
        var container = builder.Build();
        var resolver = new AutofacWebApiDependencyResolver(container);
        config.DependencyResolver = resolver;
    }
}

и мой пользовательский фильтр авторизации:

public class MyAuthorizeAttribute : AuthorizeAttribute
{
    public IAuthenticationSvc _authenticationSvc;
    protected override bool IsAuthorized(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        if (!base.IsAuthorized(actionContext))
        {
            return false;
        }
        var trueUserId = WebSecurity.CurrentUserId;

        if (_authenticationSvc.GetUsersRoles(trueUserId).Any(x => x == "Admin")) return true;
        // NullReferenceException on _authenticationSvc
     }
}

по словам официальные документы все что нужно, это:

var builder = new ContainerBuilder();
builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);

но это, кажется, тоже не делает трюк. Ценю любую помощь.

4 ответов


вы должны настроить инъекцию свойств для своего атрибута

public class MyAuthorizeAttribute : AuthorizeAttribute
{
    public IAuthenticationSvc AuthenticationSvc { get; set; }
}

строитель

builder.RegisterType<MyAuthorizeAttribute>().PropertiesAutowired();

в дополнение к ответу @Toan Nguyen, если у вас есть это...

public class MyAuthorizeAttribute : AuthorizeAttribute
{
    public IAuthenticationSvc AuthenticationSvc { get; set; }
}

... кажется, вам также нужна (или может понадобиться) первая строка ниже:

builder.RegisterFilterProvider();
builder.RegisterType<MyAuthorizeAttribute>().PropertiesAutowired();

ссылка: http://itprojectpool.blogspot.com.au/2014/03/autofac-di-on-action-filters.html


Я думаю, что документация Autofac предлагает гораздо более простое решение для фильтров действий WebApi.

public interface ServiceCallActionFilterAttribute : ActionFilterAttribute
{
  public override void OnActionExecuting(HttpActionContext actionContext)
  {
    // Get the request lifetime scope so you can resolve services.
    var requestScope = actionContext.Request.GetDependencyScope();

    // Resolve the service you want to use.
    var service = requestScope.GetService(typeof(IMyService)) as IMyService;

    // Do the rest of the work in the filter.
    service.DoWork();
  }
}

Это не "чистый DI", как он использует Service locator, но он прост и работает с областью запроса. Вам не нужно беспокоиться о регистрации конкретного фильтра действий для каждого контроллера WebApi.

источник: http://autofac.readthedocs.io/en/latest/integration/webapi.html#provide-filters-via-dependency-injection


в дополнение к настройке инъекции свойств, как указано в других ответах, вы также можете явно разрешить зависимости в OnActivating обратный.

public class MyAuthorizeAttribute : AuthorizeAttribute
{
    private IAuthenticationSvc _authenticationSvc;
    public void SetAuthenticationSvc(IAuthenticationSvc svc)
    {
       this._authenticationSvc = svc;
    }
}

и затем зарегистрировать тип:

builder.RegisterType<MyAuthorizeAttribute>()
    .OnActivating(_ => _.Instance.SetAuthenticationSvc(_.Context.Resolve<IAuthenticationSvc>()));

Примечание: Вы можете сделать то же самое свойство, а не метод. Я решил использовать метод здесь только для иллюстрации того, что это решение не зависит от PropertiesAutowired.