使用Web API和Ninject注入IOwinContext

时间:2014-05-06 17:37:29

标签: asp.net-web-api ninject owin

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

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

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

This SO question解释了如何使用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();
    }
}); 

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

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

注意

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

1 个答案:

答案 0 :(得分: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();
    }
}

您的委托处理程序:

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);
    }
}

最后将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);
}

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

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