NInject InRequest scope inside self-host owin app.

We rely a lot on per-http request owin context provided by the InRequest owin scope. However we recently started hosting some apps inside self-host, and the InRequestScope will not work inside of a self host web-api.

One workaround we have is to create a simple scope what will bind to the owin context if present, if not, fall back to httprequest.current as a scope.

To do so , we need to make sure our owin context is available at any time outside of the controller for the current thread. To do this safely, we rely on the CallContext class from System.Remoting .

public class OwinCallContext
{
    private const string OwinContextKey = "owin.IOwinContext";

    public static IOwinContext Current
    {
        get
        {
            IOwinContext ctx;

            if (System.Web.HttpContext.Current == null)
                ctx = (IOwinContext)CallContext.LogicalGetData(OwinContextKey);
            else
                ctx = (IOwinContext)System.Web.HttpContext.Current.Cache[OwinContextKey];

            return ctx;

        }
    }

    public static void Set(IOwinContext context)
    {
        if (System.Web.HttpContext.Current == null)
            CallContext.LogicalSetData(OwinContextKey, context);
        else
            System.Web.HttpContext.Current.Cache[OwinContextKey] = context;
    }

    public static void Remove(IOwinContext context)
    {
        CallContext.FreeNamedDataSlot(OwinContextKey);
    }

}

Now that we have a safe way to store per-request owin context, we need to create a simple middle ware that will provide the logical context with our owin context.

public class OwinCallContextMiddleware : OwinMiddleware
{
    IAppBuilder App { get; set; }
    public class OwinCallContextMiddleware(OwinMiddleware next, IAppBuilder app)
        : base(next)
    {
        App = app;
    }

    public async override Task Invoke(IOwinContext context)
    {
        OwinCallContext.Set(context);

        try
        {
            context.Set("AppBuilder", App);

            await Next.Invoke(context);

        }
        finally
        {
            OwinCallContext.Remove(context);
        }
    }
}

Now make sure this middleware is loaded in our pipeline

app.Use(typeof(OwinCallContextMiddleware))

Then create an extension method for your ninject bindings

public static IBindingNamedWithOrOnSyntax<T> InUnifiedRequestScope<T>(this IBindingInSyntax<T> syntax)
{
    return syntax.InScope(v => { 
    {
        if (HttpContext.Current != null)
            return HttpContext.Current;

        if (OwinCallContext.Current != null)
        {
            return OwinCallContext.Current;
        }
        else
            return System.Threading.Thread.CurrentThread;

    });

}

Submit a Comment

Your email address will not be published. Required fields are marked *

Share This