使用Autofac将依赖项注入自定义Web API操作过滤器属性

时间:2014-04-25 19:15:20

标签: asp.net-mvc asp.net-web-api dependency-injection autofac action-filter

我正在尝试解析我用于在MVC4应用中修饰API控制器的自定义AuthorizeAttribute的依赖项。问题是我一直在我的自定义过滤器中使用的服务依赖项上获得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
     }
}

根据official docs,所需要的只是:

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

但这似乎也无法解决问题。感谢任何帮助。

4 个答案:

答案 0 :(得分:23)

您应该为属性配置属性注入

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

和构建器

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

答案 1 :(得分:15)

除了@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

答案 2 :(得分:15)

我认为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”,因为它使用服务定位器,但它很简单并且适用于请求范围。您无需担心为每个WebApi控制器注册特定的操作过滤器。

来源: http://autofac.readthedocs.io/en/latest/integration/webapi.html#provide-filters-via-dependency-injection

答案 3 :(得分:1)

除了配置属性注入外(如其他答案所述),您还可以在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