0

1 つのソースからデータを取得し、操作し、データベースに保存するなど、長時間実行されるサービスがあります。

そのサービスのいくつかのメソッドを他のアプリケーションに公開したいと思います。現在、.NET Remoting を介してこれを行っていますが、WCF に移行したいと考えています。

残念ながら、私が接続するエンドポイントは、長時間実行されているサービスを介して公開したエンドポイントではありません。以下に簡単な例を示します。

    [ServiceContract]
    public interface ITestWcfService
    {
        [OperationContract]
        CounterResult GetCurrentValue();
    }

public class TestWcfService : ITestWcfService
    {
        private ITestWindowsService _service;
        public TestWcfService() { /*NOTE: For discoverability*/ }
        public TestWcfService(ITestWindowsService service)
        {
            _service = service;
        }

        public CounterResult GetCurrentValue()
        {
            return _service.GetCurrentValue();
        }
    }

public interface ITestWindowsService
    {
        CounterResult GetCurrentValue();
    }

次に、ServiceHost クラスを介して WCF サービスを自己ホストする実際の Windows サービスを作成します。

public partial class TestWindowsService : ServiceBase, ITestWindowsService
{
    private static ServiceHost _wcfService;

    public TestWindowsService()
    {
        InitializeComponent();
    }

    public void OnStart(string[] args)
    {
        //Create instance of WCF, passing in reference to this service instance
        TestWcfService wcf = new TestWcfService(this);
        _wcfService = new ServiceHost(wcf);
    }

        public CounterResult GetCurrentValue()
    {
        //Note: Some logic here
    }
}

を呼び出すたびにTestWcfServiceClient()、既定のコンストラクターを使用して Wcf サービスの新しいインスタンスを作成し、Windows サービスによって作成されたインスタンスを使用しないことを除いて、これは多かれ少なかれ機能します。これは、メンバーが設定されていないGetCurrentValue()ため、呼び出したときに null 参照を取得することを意味します。_service

私は解決策を探し回り、いくつかの引用を見つけましServiceHostFactoryたがServiceHostIInstanceProviderそれぞれが非常に複雑に見えました。

あなたが提供できるどんな考えでも大歓迎です。

編集:ここに私の ServiceModel 情報があります

<system.serviceModel>
    <services>
      <service name="WcfService.TestWcfService">
        <host>
          <baseAddresses>
            <add baseAddress = "http://localhost:8733/Design_Time_Addresses/WcfService/TestWcfService/" />
          </baseAddresses>
        </host>
        <!-- Service Endpoints -->
        <!-- Unless fully qualified, address is relative to base address supplied above -->
        <endpoint address="" binding="basicHttpBinding" contract="WcfService.ITestWcfService">
          <!-- 
              Upon deployment, the following identity element should be removed or replaced to reflect the 
              identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity 
              automatically.
          -->
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        <!-- Metadata Endpoints -->
        <!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. --> 
        <!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, 
          set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
          <!-- To receive exception details in faults for debugging purposes, 
          set the value below to true.  Set to false before deployment 
          to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
4

2 に答える 2

0

丸い穴に四角いペグを入れようとしています。

WCF は、ホスト方法に関係なく、ビジネス ロジックを呼び出すことができるように明示的に設計されています。ホスト層 (この場合は Windows のサービス) にビジネス ロジックを持つ古いリモーティング設計を維持しようとしています。その結果、WCF で可能な方法で情報をホストに戻すように求めていますが、これは見苦しく、多くの正当な理由で一般的に回避されています。

クリーンな WCF デザインが必要な場合は、抽象化レイヤーを作成し、ビジネス ロジックを既存の TestWindowsService クラスから移動する必要があります。次に、Windows サービスが WCF サービス ホストを作成し、WCF ホストが WCF サービスを作成します。WCF サービスは、それをホストするクラスに依存しません。

そうは言っても...

実際にあなたの質問に答えるには:

概念的には、作成したコードは機能するはずです。オブジェクト インスタンスを ServiceHost コンストラクターに渡すことは、カスタム IInstanceProvider の記述の複雑さを回避する最も簡単な方法です。いくつかの点を確認してください。

  1. サービス インスタンスを ServiceHost コンストラクターに渡すときは、 singletonとしてマークする必要があります。

    [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]

  2. 初期化が実際にあなたが思っているように機能していることを確認してください:

    1. サービスが null の場合にスローする TestService(ITestWindowsService) コンストラクターにガードを置きます。
    2. TestWcfService() のデフォルトのコンストラクターについて、「発見可能性のために」というコメントがあります。そのコンストラクターを削除します (少なくともトラブルシューティング中は)。コードの一部がそのコンストラクターを使用して、不要なサービス インスタンスをホストしている可能性があります。これにより、アプリが例外をスローし始めたり、実際の問題を指摘するコンパイル エラーが発生したりする可能性があります。

それでも問題が解決しない場合: app.config の Service Model セクションはどのようになっていますか?

于 2013-01-24T16:51:02.767 に答える
0

WCF は非常に拡張性がありますが、そのような拡張性を提供するには非常に複雑でもあります。私の意見では、この実装を使用したい場合は、そうすべきではありません。空のコンストラクターの代わりにカスタム コンストラクターを使用できるように、サービス ファクトリを変更する動作を作成する必要があります。

ただし、別の選択肢があるかもしれないと思います。サービスと WCF の両方が同じアプリ ドメインを共有するため、静的オブジェクトを介して値を共有できます。

基になるアセンブリに公開する値を運ぶロジックを移動します (まだ行っていない場合)。サービスと WCF サービスの両方が同じインスタンスを参照するため、すべての WCF 配管を変更する必要はありません。

于 2013-01-23T18:47:20.837 に答える