使用Castle Windsor注册OWIN IAuthenticationManager

3

由于IAuthenticationManager实现可以从OWIN上下文中检索,但Castle Windsor的组件注册必须在解析组件之前完成,那么如何注册IAuthenticationManager作为组件以便在任何地方注入?

据我所知,我应该使用Component.For<IAuthenticationManager>().UsingFactoryMethod(...),但由于我使用的是OWIN/Katana,像HttpContext.Current.GetOwinContext()这样的东西行不通(即使它能够工作,我也会讨厌为此添加对System.Web的依赖...)。

目前的解决方案是什么?


为什么你说 HttpContext.Current.GetOwinContext() 无法使用? - Phil Degenhardt
@PhilDegenhardt 我正在使用OWIN/Katana。 - Matías Fidemraizer
2个回答

2

暂时(或最终)解决方案...

这是我解决问题的方法。

首先,我实现了一个简单的OWIN中间件:

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

我已经使用 ComponentRegistration<T>.UseFactoryMethod 配置了 IAuthenticationManager,所以我实现了一个扩展方法如下:

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

最后,我是这样注册 IAuthenticationManager 的:
Component.For<IAuthenticationManager>().UseOwinComponentFactoryMethod().LifestyleTransient()

有味道...

顺便说一下,我对这个解决方案的可靠性并不自信,因为它只有在尝试在与请求不同的线程中解析组件时才能正常工作。

遗憾的是,很多情况下这种解决方案都会失败。如果你的代码实现了非阻塞IO,我预计会试图从设置“owinContext”的线程之外的另一个线程中注入IAuthenticationManager...

我仍然期待其他答案,同时寻找更好、更优雅的解决方案。


您可能希望将managedExternally: true参数添加到UsingFactoryMethod()中,以明确Windsor不负责应用任何委托/解除委托方面的问题。 - Phil Degenhardt
看起来Katana中的DI故事相当不好。在ASP.NET 5中进行了大修,应该会改善情况:http://www.emadashi.com/2015/06/dependency-injection-in-asp-net-5-one-step-deeper/ - Phil Degenhardt
@PhilDegenhardt 感谢您的建议。 - Matías Fidemraizer
有趣。我不知道CallContext类。 现在已经过去一年了。您是否仍在使用此实现从Windsor Castle访问您的OWIN上下文? - bounav
@bounav 嗯,这很奇怪。我确定它可以工作,因为我仍在开发同一项目,并且我有多个使用此方法的OWIN/Katana托管的WebAPI。可能是您实际代码中与我的不同之处... - Matías Fidemraizer
显示剩余4条评论

0

对于那些不介意依赖于 System.Web 的人,以下代码应该可以工作(而且不需要中间件)。

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

    return owinContext.Authentication;
}

然后在你的Castle Windsor安装程序中:

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

1
但是,例如在Katana托管的API中,您会分配HttpContext.Current吗?:\ - Matías Fidemraizer
@MatíasFidemraizer 是的,我忘记了不能依赖于HtppContext.Current。我正在使用IIS,所以上面的代码对我有效。不过你提醒得好。 - bounav

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接