使用Web API和Ninject注入IOwinContext

Fra*_*ans 7 ninject asp.net-web-api owin

使用Ninject的Web API 2和OWIN托管.

我想将当前的IOwinContext注入某些服务(因此我可以获取请求以使主体进行一些数据过滤).

使用Web Hosting,在过去,我会使用HttpContext.Current,但这不是OWIN托管的选项(并且很好的解决).

这个SO问题解释了如何使用Autofac.本质上,您创建一个依赖关系范围,然后在每个请求上调用Autofac的Registerinstance将当前IOwinContext注册到该依赖范围中,如下所示:

app.Use(async (ctx, next) =>
{
    // this creates a per-request, disposable scope
    using (var scope = container.BeginLifetimeScope(b =>
    {
        // this makes owin context resolvable in the scope
        b.RegisterInstance(ctx).As<IOwinContext>();
    }))
    {
        // this makes scope available for downstream frameworks
        ctx.Set<ILifetimeScope>("idsrv:AutofacScope", scope);
        await next();
    }
}); 
Run Code Online (Sandbox Code Playgroud)

那很优雅.使用Ninject和Ninject.Web.WebApi.OwinHosting我已经为每个请求获取了一个命名范围,以便管理.但是,我无法在ninject中找到任何方法来镜像AutoFac的RegisterInstance方法:这里的关键是此绑定仅在此特定依赖范围内有效.

我已经阅读了有关Scope的各种选项,但我发现的所有内容都依赖于能够声明常量或ToMethod.我在这里要做的是说,"好吧,我现在有一个ninject依赖范围,如果有人从这个范围请求IOwinContext ,给他们这个我已经拥有的实例.

注意

我确实理解我可以从我的控制器中获取当前上下文并传递它,但这反而违背了我想要做的目的; 我希望我的DbContext能够理解用户是谁,以便过滤数据.当然,一旦我可以获得IOwinContext,我实际上不会将它传递给DbContext,而是我将使用ToMethod或类似的方法来提取ClaimsPrincipal,但这超出了这个问题的范围.

Fra*_*ans 3

免责声明:这是一个黑客行为。它可以工作,但感觉很不干净。使用后果自负。

本质上,您可以创建一个 OwinContextHolder 类,将其绑定到 InRequestScope 并使用 DelegatingHandler 在每个请求上填充它。像这样的东西:

public class OwinContextHolder
{
    public IOwinContext OwinContext { get; set; }
}

public class OwinContextHolderModule : NinjectModule
{
    public override void Load()
    {
        // Instead of a NinjectModule you can of course just register the service
        this.Kernel.Bind<OwinContextHolder>().ToSelf().InRequestScope();
    }
}
Run Code Online (Sandbox Code Playgroud)

您的委托处理程序:

public class SetOwinContextHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var holder = request.GetDependencyScope().GetService(typeof(OwinContextHolder)) as OwinContextHolder;
        if (holder != null)
        {
            holder.OwinContext = request.GetOwinContext();
        }
        return base.SendAsync(request, cancellationToken);
    }
}
Run Code Online (Sandbox Code Playgroud)

最后将 DelegatingHandler 添加到您的 Startup 类中:

public void Configuration(IAppBuilder app)
{
    var webApiConfiguration = new HttpConfiguration();
    webApiConfiguration.Routes.MapHttpRoute(...);

    webApiConfiguration.MessageHandlers.Add(new SetOwinContextHandler());

    app.UseNinjectMiddleware(CreateKernel);
    app.UseNinjectWebApi(webApiConfiguration);
}
Run Code Online (Sandbox Code Playgroud)

您现在可以将 OwinContextHolder 注入到您的类中。

请注意,如果您的 API 位于与主机不同的程序集中,则可能会遇到 InRequestScope 无法正常工作的问题(例如,每次请求一个对象时都会得到一个不同的对象,并且没有错误)。如果您这样做,请参阅https://groups.google.com/forum/#!topic/ninject/Wmy83BhhFz8