2012-04-10 10 views
6

私は3つのアセンブリを作成しました。 Webサイト、WCFサービス、およびサービスが実装するインターフェイスを保持するコントラクトアセンブリ。 Castle Windsorを使用してクライアント(Webサイト)上で私のためのサービスを作成し、私が使用したい各サービスのWebサイトのWeb.configにエンドポイントを持つ必要はありません。Castle Windsor WcfFacilityを使用してクライアントエンドポイントを作成する

私は、契約アセンブリを見て、ネームスペース内のすべてのサービスインターフェイスを取得したいと考えています。今のところサービスごとに、コンテナにコンポーネントを登録するときに次のようなことがあります。

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は素晴らしいですが、ドコは少し欠けています...

答えて

12

私はwcfの機能のためのドキュメントが欠けていることに同意します。それは本当に素晴らしいツールであり、トン彼らが始めることができなかったので、それを使用するので、私ができる場合、私は少しあなたを助けることができるなら、私は見てみましょう...

さんが持っている3つのプロジェクトのアプリケーションを作成してみましょう:

  1. をクラスを共有契約のライブラリ
  2. サーバーとして動作するコンソールアプリケーション
  3. クライアント

として動作するコンソールアプリケーションのアイデアは、我々はサービスを登録するときに、サービス名を使用すると、ベースURLを共有することができるようにしたいということです(私はそれはあなたが求めていたものだと思いますもしそうでなければ、ここから外挿することができます)。だから、まず、共有契約は、単にその中にこの(何も特別な、通常のWCF運賃)があります。

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

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

をサーバコンソールアプリケーションは次のようになり、私たちはまずただ、そこに何も特別再び(サービス契約を実装していませんインターフェイスを実装しているクラス)、すべてをサービスとして登録するだけです(設定ファイルは必要ありません。ウィンザーが提供するすべてのオプションを使用して、サービスなどを決める方法を変更できます)。あなたにアイデアを与えます):

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を構築しているかを確認できるはずです。そうすれば、基本ファイルを設定ファイルなどから簡単に取り出すことができます。

言及する最後の事はあなたがこのようなものだろうクライアントの例のように、あなたは、エンドポイントへの拡張として、それを追加することで、カスタムエンドポイント動作を追加できることです

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

のように動作します魅力、ありがとうございました。 –

+0

これは何をしますか? (f => f.CloseTimeout = TimeSpan.Zero) –

+0

これは、すべてのサービスのデフォルトのクローズタイムアウトを設定します。これは、「クローズ操作が完了するまでの時間間隔を指定するTimeSpan値です。ゼロに等しい。デフォルトは00:01:00である。 - http://msdn.microsoft.com/en-us/library/ms731361.aspxから。また、ここにはすべての可能なタイムアウトについての良いスレッドがあります。http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/84551e45-19a2-4d0d-bcc0-516a4041943d/ – kmp

関連する問題