7

3 つのアセンブリを作成しました。Web サイト、WCF サービス、およびサービスが実装するインターフェイスを保持するコントラクト アセンブリ。Castle Windsor を使用してクライアント (Web サイト) でサービスを作成し、使用するサービスごとに Web サイトの 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 は良さそうですが、ドコはちょっと物足りない…

4

1 に答える 1

13

wcf 機能のドキュメントが不足していることに同意します。これは本当に素晴らしいツールであり、開始できなかったために使用しなかった場合は本当に残念なことです。できれば少し出て...

以下を持つ 3 つのプロジェクト アプリケーションを作成しましょう。

  1. 共有コントラクト用のクラス ライブラリ
  2. サーバーとして機能するコンソール アプリケーション
  3. クライアントとして機能するコンソール アプリケーション

アイデアは、サービスを登録するときにサービス名を使用してベース 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())
于 2012-04-11T06:34:07.447 に答える