You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ASP WebApi中使用带Ninject构造注入参数的ActionFilterAttribute?

在ASP WebApi中使用带Ninject构造注入的ActionFilterAttribute

当然可以实现!我之前也踩过这个坑——Mvc里直接用构造注入过滤器很顺畅,但WebApi的过滤器实例化逻辑和Mvc不一样,默认不走DI容器,所以得做点额外配置。下面是我亲测有效的方案:

核心思路

WebApi默认通过Activator.CreateInstance直接实例化过滤器,不会经过你的Ninject容器,所以带参数的构造函数会直接报错。解决办法是替换WebApi的默认过滤器提供器,让它从Ninject容器中获取过滤器实例,这样就能支持构造注入了。

分步实现

1. 定义过滤器和依赖接口

先把需要注入的依赖抽成接口,过滤器通过构造函数接收这个依赖:

// 依赖接口
public interface IFilterDependency
{
    void ValidateRequest();
}

// 依赖实现
public class FilterDependency : IFilterDependency
{
    public void ValidateRequest()
    {
        // 这里写你的业务逻辑,比如权限校验、日志记录等
    }
}

// 带构造注入的过滤器
public class InjectedApiFilter : ActionFilterAttribute
{
    private readonly IFilterDependency _dependency;

    // 构造函数接收依赖,由Ninject注入
    public InjectedApiFilter(IFilterDependency dependency)
    {
        _dependency = dependency ?? throw new ArgumentNullException(nameof(dependency));
    }

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        // 使用注入的依赖
        _dependency.ValidateRequest();
        base.OnActionExecuting(actionContext);
    }
}

2. 实现自定义Ninject过滤器提供器

创建一个实现IFilterProvider的类,让它从Ninject容器中解析过滤器:

public class NinjectFilterProvider : IFilterProvider
{
    private readonly IKernel _ninjectKernel;

    public NinjectFilterProvider(IKernel kernel)
    {
        _ninjectKernel = kernel;
    }

    public IEnumerable<FilterInfo> GetFilters(HttpConfiguration config, HttpActionDescriptor actionDescriptor)
    {
        // 解析控制器上的过滤器
        foreach (var attr in actionDescriptor.ControllerDescriptor.GetCustomAttributes<FilterAttribute>(inherit: true))
        {
            yield return new FilterInfo(ResolveFilter(attr), FilterScope.Controller);
        }

        // 解析动作上的过滤器
        foreach (var attr in actionDescriptor.GetCustomAttributes<FilterAttribute>(inherit: true))
        {
            yield return new FilterInfo(ResolveFilter(attr), FilterScope.Action);
        }
    }

    private FilterAttribute ResolveFilter(FilterAttribute filterAttr)
    {
        // 如果过滤器类型已在Ninject注册,就从容器获取实例,否则返回原实例
        var filterType = filterAttr.GetType();
        return _ninjectKernel.Get(filterType) as FilterAttribute ?? filterAttr;
    }
}

3. 注册依赖和替换过滤器提供器

在WebApiConfig.cs的Register方法中,完成Ninject的依赖注册和过滤器提供器替换:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // 初始化Ninject内核
        var kernel = new StandardKernel();

        // 注册你的依赖和过滤器
        kernel.Bind<IFilterDependency>().To<FilterDependency>();
        kernel.Bind<InjectedApiFilter>().ToSelf();

        // 移除WebApi默认的过滤器提供器,替换成我们的Ninject版本
        config.Services.RemoveAll(typeof(IFilterProvider), provider => provider is ActionDescriptorFilterProvider);
        config.Services.Add(typeof(IFilterProvider), new NinjectFilterProvider(kernel));

        // 常规WebApi路由配置
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

4. 在控制器/动作上使用过滤器

现在就可以像普通过滤器一样标记了,Ninject会自动注入构造参数:

[InjectedApiFilter]
public class ProductsController : ApiController
{
    // 控制器动作...
}

备选方案:服务定位器模式(不推荐)

如果你不想替换整个过滤器提供器,也可以在过滤器内部通过WebApi的依赖解析器获取依赖,但这种方式会增加耦合,不推荐用于大型项目:

public class InjectedApiFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        var dependency = actionContext.Request.GetDependencyResolver()
            .GetService(typeof(IFilterDependency)) as IFilterDependency;
        
        dependency?.ValidateRequest();
        base.OnActionExecuting(actionContext);
    }
}

关键注意点

  • 一定要移除WebApi默认的ActionDescriptorFilterProvider,否则它会和我们的自定义提供器冲突,导致过滤器被实例化两次。
  • 确保所有需要注入的过滤器都在Ninject中完成注册,不然自定义提供器会返回原实例,构造注入会失败。

内容的提问来源于stack exchange,提问作者neuser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:03:18