Inject IOwinContext with Web API and Ninject

Using Web API 2 and hosting OWIN with Ninject.

I would like to inject the current IOwinContext into certain services (so I can get in the request to get the directors to do some data filtering).

With web hosting, in the old days I would just use HttpContext.Current, but this is not an option with OWIN hosting (and a good disposal).

This SO question explains how to do this with Autofac. Essentially, you create a dependency region, and then, for each request, calls Autofac Registerinstance to register the current IOwinContext in this dependency region as follows:

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

It is very elegant. With Ninject and Ninject.Web.WebApi.OwinHosting, I already get named areas for each request to take care of the plumbing. However, I could not find any way in ninject to mirror the AutoFac RegisterInstance method: The key here is that this binding is only valid in this particular dependency area.

I read various options around Scope, but all I found relies on the ability to declare constants or ToMethod. What I want to do here is to say: "OK, now I have a ninject dependency area, and if someone requests an IOwinContext from this area, give them that instance that I already have.

Note

I understand that I can get the current context from my controller and pass it on, but it rather hits the target of what I'm trying to do; I want my DbContext to understand who the user is so that he can filter the data. And of course, as soon as I can get the IOwinContext, I will not actually pass this to the DbContext, rather I will use ToMethod or similar to retrieve ClaimsPrincipal, but that is beyond the scope of this question.

+7
asp.net-web-api ninject owin
source share
1 answer

DISCLAIMER: This is a hack. He works, but he feels very unclean. Use your danger.

In essence, you can create an OwinContextHolder class, bind it to InRequestScope, and use the DelegatingHandler to populate it for each request. Something like that:

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

Your delegation handler:

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

Finally, add the DelegatingHandler to your startup class:

 public void Configuration(IAppBuilder app) { var webApiConfiguration = new HttpConfiguration(); webApiConfiguration.Routes.MapHttpRoute(...); webApiConfiguration.MessageHandlers.Add(new SetOwinContextHandler()); app.UseNinjectMiddleware(CreateKernel); app.UseNinjectWebApi(webApiConfiguration); } 

Now you can introduce OwinContextHolder into your classes.

Please note: if you have an API in a separate assembly from your host, you may have problems with the fact that InRequestScope silently does not work (like, you get a different object every time you request one and without errors). If you do, see https://groups.google.com/forum/#!topic/ninject/Wmy83BhhFz8 .

+3
source share

All Articles