【发布时间】: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
().ToMethod(c => session).InRequestScope();会话是在请求中创建的,但按请求使用。解决方案是将会话的打开移动到每个请求调用中: Bind ().ToMethod( c => sessionFactory.OpenSession()).InRequestScope();我与之抗争的另一件事是确保您始终在使用 WebApi 与 MVC 时保持同步。很多时候名称是相同的,只是名称空间不同。 -
感谢您的回复。我的问题最终是 WebAPI 缓存了过滤器,所以我的构造函数依赖项只注入了一次。