使用 Ninject BindHttpFilter 时的范围问题
Posted
技术标签:
【中文标题】使用 Ninject BindHttpFilter 时的范围问题【英文标题】:Scope issues when using Ninject BindHttpFilter 【发布时间】:2014-10-29 18:27:50 【问题描述】:我有一个 WebApi 服务,我正在尝试使用 Ninject BindHttpFilter 添加身份验证。
使用 BindHttpFilter 可以将身份验证过滤器绑定到特定属性。 AuthenticationFilter 接受一个构造函数参数(IAuthenticationService),它本身是由 Ninject 创建的。
kernel.BindHttpFilter<AuthenticationHttpFilter>(System.Web.Http.Filters.FilterScope.Action)
.WhenActionMethodHas<AuthenticationFilterAttribute>()
.WithConstructorArgument("service", x => x.Kernel.Get<IAuthenticationService>());
AuthenticationService 的具体实现采用了一个构造函数参数 INonceRepository,通过 Ninject 注入:
public AuthenticationService(INonceRepository nonceRepository, ...)
NonceRepository 的具体实现采用了一个通过 Ninject 注入的构造函数 ISession:
public NonceRepository(ISession session)
Ninject 绑定如下所示:
kernel.Bind<INonceRepository>().To<NonceRepository>();
kernel.Bind<IAuthenticationService>().To<AuthenticationService>()
var session = sessionFactory.OpenSession();
Bind<ISession>().ToMethod(c => session).InRequestScope();
当代码运行时,AuthenticationService 的具体实现只被实例化一次,因此 NonceRepositiory 只被实例化一次。这意味着 ISession 有效并打开第一个请求,但 ISession 在第二次调用时关闭,并且第二次调用 AuthenticationService 的构造函数。这似乎是一个范围问题,但我无法弄清楚什么没有正确的范围来使 AuthenticationService 根据请求重新创建。
我尝试将 BindHttpScope 请求从 FilterScope.Controller 更改为 FilterScope.Action(认为这会导致 AuthenticationService 的范围是它是每个 Action 调用创建的),但这并没有解决问题。
下面是代码的有趣点:
public class AuthenticationHttpFilter : IAuthenticationFilter
private readonly IAuthenticationService authenticationService;
public AuthenticationHttpFilter(IAuthenticationService service)
this.authenticationService = service;
public bool AllowMultiple get; private set;
public Task AuthenticateAsync(HttpAuthenticationContext authenticationContext, CancellationToken cancellationToken)
authenticationService.DoAuth();
return Task.FromResult(0);
public Task ChallengeAsync(HttpAuthenticationChallengeContext authenticationChallengeContext, CancellationToken cancellationToken)
...
public class AuthenticationService : IAuthenticationService
private readonly INonceRepository nonceRepo;
public AuthenticationService(INonceRepository nonceRepo)...
public void DoAuth()
this.nonceRepo.Add(...);
public class NonceRepository : INonceRepository
private readonly ISession _session;
public NonceRepository(ISession session)
this._session = session;
public void Add(Nonce nonce)
this._session.Save(nonce);
【问题讨论】:
肯特,你解决过这个问题吗?我有一个非常相似的问题。 Jason,我回来了一点,但是......我相信问题是: var session = sessionFactory.OpenSession(); Bind我发现当我使用 WebApi 2 时,一切正常。它在 RequestScope 中的行为与我预期的一样。但是,在使用 MVC 5 时,过滤器会一直缓存在管道中,这会将构造函数参数保持在“Singleton”范围内。
我通过像这样进入actionContext
的配置解决了这个问题:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class EventGridFilterAttribute : ActionFilterAttribute
private readonly Type serviceType = typeof(IEventGridService);
public EventGridFilterAttribute()
public override async Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
var service = actionExecutedContext?.ActionContext?.ControllerContext?.Configuration?.DependencyResolver?.GetService(serviceType) as IEventGridService;
if (service != null && actionExecutedContext.Exception == null)
await service.PublishEventsAsync();
await base.OnActionExecutedAsync(actionExecutedContext, cancellationToken);
我的依赖注入器保存在这里。
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
我也不使用BindHttpFilter
,而是像普通过滤器一样注册我的过滤器。
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
filters.Add(new EventGridFilterAttribute());
【讨论】:
以上是关于使用 Ninject BindHttpFilter 时的范围问题的主要内容,如果未能解决你的问题,请参考以下文章
Ninject 在使用 NinjectHttpModule 时创建一个额外的实例
ninject 继承安全规则违反了类型:mvc4 中的“Ninject.Web.Mvc.Filter.FilterContextParameter”