我的应用程序使用“SignalR”客户端/服务器通信框架。如果您不熟悉它,服务器端应用程序通常包含一个或多个“集线器”类(类似于asmx Web服务),每个类提供可由客户端调用的方法。在启动期间,客户端需要首先创建连接,然后为每个需要与之通信的集线器创建“代理”,例如: -
var hubConnection = new HubConnection("http://...");
var fooHubProxy = hubConnection.CreateHubProxy("FooHub");
var barHubProxy = hubConnection.CreateHubProxy("BarHub");
...etc...
传递给CreateHubProxy()
的字符串参数是服务器端集线器类的名称。方法返回类型为IHubProxy
。
感觉我应该能够在这里使用温莎,但我很难找到解决方案。我的第一个想法是实例化集线器代理并使用Windsor(按名称)注册这些实例,例如。
var fooHubProxy = hubConnection.CreateHubProxy("FooHub");
container.Register(Component.For<IHubProxy>().Instance(fooHubProxy).LifestyleSingleton().Named("FooHub"));
...etc...
问题是当一个类需要一个集线器代理时,按名称解析它的唯一方法是使用服务定位器模式,这是不推荐的。 Windsor的其他功能(例如打字的工厂等)在这里可能有用吗?
修改
我刚刚找到Windsor的.UsingFactoryMethod
,我想知道这是否有效,以简化集线器注册:
container.Register(Component.For<IHubProxy>()
.UsingFactoryMethod((kernel, context) => hubConnection.CreateHubProxy("FooHub"))
.LifestyleSingleton()
.Named("FooHub"));
我想我仍然有如何通过名字解决的问题。
答案 0 :(得分:4)
两年后,但是对于其他人来说,我也有一个更优雅的解决方案。 可以使用TypedFactory工具并根据您的需要进行调整,如here。 首先创建工厂界面(仅!不需要实际实现,城堡将负责):
public interface IHubProxyFactory
{
IHubProxy GetProxy(string proxyName);
}
现在我们需要一个扩展默认类型facotory的类,并从输入(proxyName
)中检索组件的名称:
class NamedTypeFactory : DefaultTypedFactoryComponentSelector
{
protected override string GetComponentName(MethodInfo method, object[] arguments)
{
string componentName = null;
if (arguments!= null && arguments.Length > 0)
{
componentName = arguments[0] as string;
}
if (string.IsNullOrEmpty(componentName))
componentName = base.GetComponentName(method, arguments);
return componentName;
}
}
然后使用castle注册工厂并指定将使用NamedTypeFactory:
Component.For<IHubProxyFactory>().AsFactory(new NamedTypeFactory())
现在每个类都可以在其构造函数中获取工厂接口:
public class SomeClass
{
private IHubProxy _fooHub;
private IHubProxy _barHub;
public SomeClass(IHubProxyFactory hubProxyFactory)
{
_fooHub = hubProxyFactory.GetProxy("FooHub");
_barHub = hubProxyFactory.GetProxy("BarHub");
}
}
答案 1 :(得分:2)
好的,我想我找到了一个可能的解决方案,部分使用了详细的here方法,该方法显示了如何向温莎注册Func<>
。
首先,我注册一个使用容器按名称解析的委托(Func&lt;&gt;): -
Container.Register(Component.For<Func<string, IHubProxy>>()
.Instance(name => Container.Resolve<IHubProxy>(name))
.LifestyleSingleton());
将此视为IHubProxy“工厂”。
接下来,我按照原始问题详细说明了我的中心代理: -
container.Register(Component.For<IHubProxy>()
.UsingFactoryMethod((kernel, context) => hubConnection.CreateHubProxy("FooHub"))
.LifestyleSingleton()
.Named("FooHub"));
container.Register(Component.For<IHubProxy>()
.UsingFactoryMethod((kernel, context) => hubConnection.CreateHubProxy("BarHub"))
.LifestyleSingleton()
.Named("BarHub"));
以下是需要集线器代理实例的类的示例: -
public class SomeClass
{
private IHubProxy _fooHub;
private IHubProxy _barHub;
public SomeClass(Func<string, IHubProxy> hubProxyFactory)
{
_fooHub = hubProxyFactory("FooHub");
_barHub = hubProxyFactory("BarHub");
}
}
目前尚未尝试,但看起来很有希望。这是一个聪明的解决方案,但注入Func&lt;&gt;感觉有点hacky,所以我仍然希望听到其他可能解决我问题的方法。
答案 2 :(得分:1)
我刚用你的方法。我使用的是打字工厂。优点是我的集线器具有类型安全性。注册集线器是一样的。其余的有点不同,但技术上是一样的。
IServiceFactory {
IHubProxy GetFooHub();
IHubProxy GetBarHub();
}
注册:
Container.AddFacility<TypedFactoryFacility>();
Container.Register(Component.For<IServiceFactory>().AsFactory());
用法:
public class SomeClass
{
private IHubProxy _fooHub;
private IHubProxy _barHub;
public SomeClass(IServiceFactry hubProxyFactory)
{
_fooHub = hubProxyFactory.GetFooHub();
_barHub = hubProxyFactory.GetBarHub();
}
}
顺便说一下。 Factory.Get"Name"()
按名称解析。