3

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

AFAIK,我应该使用Component.For<IAuthenticationManager>().UsingFactoryMethod(...),但由于我使用的是 OWIN/Katana,所以类似的东西HttpContext.Current.GetOwinContext()不起作用(如果它起作用,我不想为此添加依赖项System.Web......)。

现在有什么解决方案?

4

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

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

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

它闻起来臭臭的...

顺便说一句,我不相信该解决方案的可靠性,因为除非您尝试在请求线程之外的另一个线程中解析组件,否则它应该可以工作。

可悲的是,这种解决方案应该在很多情况下都可能失败。如果您的代码实现了非阻塞 I/O,我希望尝试IAuthenticationManager从另一个线程注入在CallContext...

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

于 2015-08-05T09:59:34.513 回答
0

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

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

    return owinContext.Authentication;
}

然后在您的城堡温莎安装程序中:

container.Register(Component.For<IAuthenticationManager>()
                            .UsingFactoryMethod(GetAuthenticationManager, managedExternally: true)
                            .LifestyleTransient())
于 2016-11-19T13:01:10.800 回答