Matías Fidemraizer
Matías Fidemraizer

Reputation: 64923

Registering OWIN IAuthenticationManager using Castle Windsor

Since IAuthenticationManager implementation can be retrieved from OWIN context, but Castle Windsor's component registration must be done before resolving components, how can I register IAuthenticationManager as component to get injected anywhere?

AFAIK, I should use Component.For<IAuthenticationManager>().UsingFactoryMethod(...), but since I'm using OWIN/Katana, something like HttpContext.Current.GetOwinContext() won't work (and if it would work, I would hate to add a dependency to System.Web for this...).

What's the solution for this right now?

Upvotes: 3

Views: 1133

Answers (2)

bounav
bounav

Reputation: 5046

For those who don't mind having a dependency to System.Web, the following code should work (and it doesn't require a middleware).

private static IAuthenticationManager GetAuthenticationManager(IKernel kernel, ComponentModel componentModel, CreationContext creationContext)
{
    var owinContext = new HttpContextWrapper(HttpContext.Current).GetOwinContext();

    return owinContext.Authentication;
}

Then in your castle windsor installer:

container.Register(Component.For<IAuthenticationManager>()
                            .UsingFactoryMethod(GetAuthenticationManager, managedExternally: true)
                            .LifestyleTransient())

Upvotes: 0

Mat&#237;as Fidemraizer
Mat&#237;as Fidemraizer

Reputation: 64923

Temporal (or definitive) solution...

This is how I've managed to solve the issue.

First of all, I've implemented a simple OWIN middleware:

public sealed class WindsorMiddleware : OwinMiddleware
{
    public WindsorMiddleware(OwinMiddleware next) : base(next)
    {
    }

    public override async Task Invoke(IOwinContext context)
    {
        CallContext.LogicalSetData("owinContext", context);

        await Next.Invoke(context);

        CallContext.FreeNamedDataSlot("owinContext");
    }
}

And I've configured IAuthenticationManager using ComponentRegistration<T>.UseFactoryMethod so I've implemented an extension method like this:

public static ComponentRegistration<TService> UseOwinComponentFactoryMethod<TService>(this ComponentRegistration<TService> registration)
    where TService : class
{
    return registration.UsingFactoryMethod
    (
        (kernel, componentModel, creationContext) =>
        {
            IOwinContext owinContext = CallContext.LogicalGetData("owinContext") as IOwinContext;

            Contract.Assert(owinContext != null);

            if (creationContext.RequestedType == typeof(IAuthenticationManager))
            {
                return (TService)owinContext.Authentication;
            }
            else
            {
                throw new NotSupportedException();
            }
        },
        managedExternally: true
    );
}

Finally, I've registered IAuthenticationManager this way:

Component.For<IAuthenticationManager>().UseOwinComponentFactoryMethod().LifestyleTransient()

It smells...

BTW, I'm not self-convinced about the reliability of this solution since this should work unless you try to resolve components in another thread than the request one.

Sadly, it should be a lot of situations where this solution can fail. If your code implements non-blocking I/O, I expect to try to inject IAuthenticationManager from another thread from the one that set "owinContext" in the CallContext...

I'll still look forward for other answers while I find a better and more elegant solution.

Upvotes: 2

Related Questions