使用Castle Windsor WcfFacility创建客户端端点

时间:2012-04-10 08:01:14

标签: wcf castle-windsor ioc-container wcf-endpoint wcffacility

我创建了三个程序集。 Web站点,WCF服务和包含服务实现的接口的合同程序集。我想使用Castle Windsor在客户端(网站)上为我创建服务,这样我就不必在网站的web.config中为我希望使用的每个服务都有一个端点。

我想查看契约程序集并获取命名空间中的所有服务接口。现在,对于每个服务,我在使用容器注册组件时都会遇到以下情况。

container.Register(Component.For<ChannelFactory<IMyService>>().DependsOn(new { endpointConfigurationName = "MyServiceEndpoint" }).LifeStyle.Singleton);
container.Register(Component.For<IMyService>().UsingFactoryMethod((kernel, creationContext) => kernel.Resolve<ChannelFactory<IMyService>>().CreateChannel()).LifeStyle.PerWebRequest);

在我的web.config中我有设置代码。

  <system.serviceModel>
      <extensions>
         <behaviorExtensions>
            <add name="AuthToken" type="MyNamespace.Infrastructure.AuthTokenBehavior, MyNamespace.Contracts" />
         </behaviorExtensions>
      </extensions>
      <behaviors>
         <endpointBehaviors>
            <behavior>
               <AuthToken />
            </behavior>
         </endpointBehaviors>
      </behaviors>

      <bindings>
         <wsHttpBinding>
            <binding maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00">
               <readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647"></readerQuotas>
               <security mode="None" />
            </binding>
         </wsHttpBinding>
      </bindings>

      <client>
         <endpoint name="MyServiceEndpoint" address="http://someurl/MyService.svc" binding="wsHttpBinding" contract="MyNamespace.Contracts.IMyService"></endpoint>
      </client>
   </system.serviceModel>

我最终得到的服务端点看起来几乎完全相同,当我们部署到客户端机器上时,他们必须设置每个端点的地址,即使每个端点的基本URL都相同。

我想在我的web.config中有一个基本URL,它通过代码获取,然后使用合同程序集上的反射在容器中注册服务。我确实需要上面配置文件中的专门端点行为。

我从哪里开始? WcfFacility看起来很棒但是doco有点缺乏......

1 个答案:

答案 0 :(得分:13)

我同意wcf设施的文档缺乏,这很可悲,因为它是一个非常好的工具,如果人们因为无法启动而没有使用它将是一个真正的耻辱,所以让我看看是否如果可以,我可以帮助你一点......

让我们创建一个具有以下内容的三个项目应用程序:

  1. 共享合同的类库
  2. 充当服务器的控制台应用程序
  3. 充当客户端的控制台应用程序
  4. 我们的想法是,我们希望能够在注册服务时使用服务名称并共享基本URL(我认为这就是您所要求的,如果没有,希望您可以从这里进行推断)。所以,首先,共享合同中只有它(没有什么特别的,正常的WCF票价):

    [ServiceContract]
    public interface IMyService1
    {
        [OperationContract]
        void DoSomething();
    }
    
    [ServiceContract]
    public interface IMyService2
    {
        [OperationContract]
        void DoSomethingToo();
    }
    

    现在服务器控制台应用程序看起来像这样,我们首先实现服务契约(再没有什么特别的,只是实现接口的类)然后只将它们全部注册为服务(注意这里不需要任何配置文件,你可以改变你使用Windsor给你的所有选项决定什么是服务等的方式 - 我的方案有点受限,但它给你一个想法):

    namespace Services
    {
        public class MyService1 : IMyService1
        {
            public void DoSomething()
            {
            }
        }
    
        public class MyService2 : IMyService2
        {
            public void DoSomethingToo()
            {
            }
        }
    }
    
    //... In some other namespace...
    
    class Program
    {
        // Console application main
        static void Main()
        {
            // Construct the container, add the facility and then register all
            // the types in the same namespace as the MyService1 implementation
            // as WCF services using the name as the URL (so for example 
            // MyService1 would be http://localhost/MyServices/MyService1) and
            // with the default interface as teh service contract
            var container = new WindsorContainer();            
            container.AddFacility<WcfFacility>(
                f => f.CloseTimeout = TimeSpan.Zero);
            container
                .Register(
                    AllTypes
                        .FromThisAssembly()
                        .InSameNamespaceAs<MyService1>()
                        .WithServiceDefaultInterfaces()
                        .Configure(c =>
                                   c.Named(c.Implementation.Name)
                                       .AsWcfService(
                                           new DefaultServiceModel()
                                               .AddEndpoints(WcfEndpoint
                                                                 .BoundTo(new WSHttpBinding())
                                                                 .At(string.Format(
                                                                     "http://localhost/MyServices/{0}",
                                                                     c.Implementation.Name)
                                                                 )))));
    
            // Now just wait for a Q before shutting down
            while (Console.ReadKey().Key != ConsoleKey.Q)
            {
            }
        }
    }
    

    那就是服务器,现在如何使用这些服务?嗯,实际上这很简单,这是一个客户端控制台应用程序(它只引用契约类库):

    class Program
    {
        static void Main()
        {
            // Create the container, add the facilty and then use all the
            // interfaces in the same namespace as IMyService1 in the assembly 
            // that contains the aforementioned namesapce as WCF client proxies
            IWindsorContainer container = new WindsorContainer();
    
            container.AddFacility<WcfFacility>(
                f => f.CloseTimeout = TimeSpan.Zero);
    
            container
                .Register(
                    Types
                        .FromAssemblyContaining<IMyService1>()
                        .InSameNamespaceAs<IMyService1>()
                        .Configure(
                            c => c.Named(c.Implementation.Name)
                                     .AsWcfClient(new DefaultClientModel
                                                      {
                                                          Endpoint = WcfEndpoint
                                                              .BoundTo(new WSHttpBinding())
                                                              .At(string.Format(
                                                                  "http://localhost/MyServices/{0}",
                                                                  c.Name.Substring(1)))
                                                      })));
    
            // Now we just resolve them from the container and call an operation
            // to test it - of course, now they are in the container you can get
            // hold of them just like any other Castle registered component
            var service1 = container.Resolve<IMyService1>();
            service1.DoSomething();
    
            var service2 = container.Resolve<IMyService2>();
            service2.DoSomethingToo();
        }
    }
    

    就是这样 - 希望这会让你开始(我发现实验并使用智能感知通常会让我到达我需要去的地方)。我向您展示了服务和客户方面,但如果您愿意,可以使用其中一个。

    您应该能够看到绑定的配置位置以及我如何构建URL,因此在您的情况下,您可以轻松地从配置文件或任何您想要的操作中提取基本URL。

    最后要提到的是,您可以通过将其添加为端点的扩展来添加自定义端点行为,因此在客户端示例中,您将具有以下内容:

    Endpoint = WcfEndpoint
        .BoundTo(new WSHttpBinding())
        .At(string.Format("http://localhost/MyServices/{0}", c.Name.Substring(1)))
        .AddExtensions(new AuthTokenBehavior())