【问题标题】:Castle Windsor - how to resolve by name?温莎城堡 - 如何通过名称解决?
【发布时间】:2014-02-13 11:05:58
【问题描述】:

我的应用程序使用“SignalR”客户端/服务器通信框架。如果您不熟悉它,服务器端应用程序通常包含一个或多个“集线器”类(类似于 asmx Web 服务),每个都提供可由客户端调用的方法。在启动期间,客户端需要首先创建一个连接,然后为需要与之通信的每个集线器创建一个“代理”,例如:-

var hubConnection = new HubConnection("http://...");
var fooHubProxy = hubConnection.CreateHubProxy("FooHub");
var barHubProxy = hubConnection.CreateHubProxy("BarHub");
...etc...

传递给CreateHubProxy() 的字符串参数是服务器端集线器类的名称。方法返回类型为IHubProxy

感觉我应该可以在这里使用 Windsor,但我正在努力寻找解决方案。我的第一个想法是实例化集线器代理并将这些实例注册到 Windsor(按名称),例如

var fooHubProxy = hubConnection.CreateHubProxy("FooHub");
container.Register(Component.For<IHubProxy>().Instance(fooHubProxy).LifestyleSingleton().Named("FooHub"));
...etc...

问题是当一个类需要一个 hub 代理时,通过名称来解决它的唯一方法是使用服务定位器模式,不推荐这样做。还有哪些其他 Windsor 功能(例如类型化工厂等)可能在这里有用?

编辑

我刚刚找到了 Windsor 的 .UsingFactoryMethod,想知道这是否可行,以简化中心注册:

container.Register(Component.For<IHubProxy>()
                   .UsingFactoryMethod((kernel, context) => hubConnection.CreateHubProxy("FooHub"))
                   .LifestyleSingleton()
                   .Named("FooHub"));

我想我仍然有如何通过名称解决的问题。

【问题讨论】:

    标签: castle-windsor


    【解决方案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"() 按名称解析。

    【讨论】:

      【解决方案2】:

      两年后,但我为其他也遇到此问题的人提供了一个更优雅的解决方案。 可以使用 TypedFactory 工具并使其适应您的需求,例如 here。 首先创建工厂接口(仅!不需要实际实现,城堡会处理):

      public interface IHubProxyFactory
      {
         IHubProxy GetProxy(string proxyName);
      }
      

      现在我们需要一个扩展默认类型化工厂并从输入 (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;
          }
      }
      

      然后将工厂注册到城堡并指定将使用您的 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");
          }
      }
      

      【讨论】:

        【解决方案3】:

        好的,我想我找到了一个可能的解决方案,部分使用了详细的here 方法,该方法显示了如何在 Windsor 中注册Func&lt;&gt;s。

        首先,我注册了一个委托(Func),它使用容器按名称解析:-

        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 感觉有点笨拙,所以我仍然很想听到其他可能的解决方案来解决我的问题。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-08-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多