4

サービスの進行状況を時々通知するクライアント アプリケーションがあります。サービスへのメソッド呼び出しは、IsOneWay=true でマークされています。これは、通知に戻り値が必要なく、遅延させたくないためです。

クライアントはサービスにエラーを通知し、その後終了します。

問題は、メッセージを送信した後、一方向のメソッド呼び出しが呼び出し元のコードに戻るかどうかです。または、メッセージをキューに入れ、後で別のスレッドによって送信されますか?

2 つのプロセス (クライアントとサービス) は同じマシン上にありますが、(マシンが過負荷になっていると) サービスがエラー通知を受け取れないことがあります。私が言及した 2 番目のオプションが発生すると思われますが、よくわかりません。

私が正しければ、通知が送信されていることを確認し、メソッドを一方向に保つにはどうすればよいですか?

4

6 に答える 6

8

良い質問。クライアント アプリケーションは、メソッドを呼び出す前にチャネルを開きます。チャネルはすべてのデータ通信に使用されます。送信には 2 つの方法があります: 1) 信頼できるセッション - パケットが確実に配信され、クラックされたパケットが再送信される場合、2) 順序付け - サービスのリクエストがクライアントから転送された順序で計算される場合 (配信方法ではありません) . 信頼性の高い順序付けされたセッションがあり、アプリケーションを閉じた後にサービスホストがデータに問題を抱えている場合、ホストはクライアントに再送信データを要求しようとし、応答がない場合、要求したものをすべて拒否します。他の状況(信頼できない)では、チャネルを開いた後、データを送信して通信を破棄できます。例外がなければ、一方向メソッドがリクエストを計算します。

サービスの問題でいくつかの可能性をテストするために(正確にはクライアントのパロブレムではありませんが、役に立ちます)、解決策を作成します:

1) 1 つのファイル「IService1.cs」を含むライブラリ プロジェクト「WcfContracts」:

    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        void ThrowException();

        [OperationContract(IsOneWay=true)]
        void ThrowExceptionUseIsOneWay();
    }

2) 2 つの「WcfContracts」を参照するコンソール プロジェクト「WcfConsoleHoster」は、次の 3 つのファイルで構成されます。

a) サービスの実装である Service1.cs

public class Service1 : WcfContracts.IService1
{    
        public void ThrowException()
        {
            throw new Exception("Basic exception");
        }

        public void ThrowExceptionUseIsOneWay()
        {
            throw new Exception("Basic exception using IsOneWay=true");
        }
}

b) デフォルトのエントリ ポイントがあり、サービスを開始するだけの Program.cs

static void Main(string[] args)
    {
        ServiceHost host = new ServiceHost(typeof(Service1));
        host.Open();
        Console.WriteLine("host 1 opened");
        Console.ReadKey();
    }

c) サービス「App.config」

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="behavourHttpGet" name="WcfConsoleHoster.Service1">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8732/Design_Time_Addresses/WcfConsoleHoster/Service1/" />
          </baseAddresses>
        </host>
        <endpoint binding="wsHttpBinding" contract="WcfContracts.IService1" />        
        <endpoint address ="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="behavourHttpGet">
          <serviceMetadata httpGetEnabled="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

3) サービスを呼び出すだけのコンソール プロジェクト「WcfConsoleClient」

a) 「Program.cs」内

Console.WriteLine("Wcf client. Press any key to start");
Console.ReadKey();
ChannelFactory<IService1> factory = new ChannelFactory<IService1>("Service1_Endpoint");
IService1 channel = factory.CreateChannel();
//Call service method
channel.ThrowException();

Console.WriteLine("Operation executed");
Console.ReadKey();

b) クライアント「App.config」

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <client>
      <endpoint name="Service1_Endpoint"
        address="http://localhost:8732/Design_Time_Addresses/WcfConsoleHoster/Service1/"
        binding="wsHttpBinding"
        contract="WcfContracts.IService1">
      </endpoint>
    </client>
  </system.serviceModel>
</configuration>

1.例外をスローします。まず、サーバー ホストで例外をスローする双方向メソッドを呼び出します。次に、この例外はクライアントに戻り、チャネルはクライアント側でそれを発生させ、アプリケーションは破棄されます。もちろん、これは try()catch{} ブロックで処理できます。

を呼び出して一方向メソッドで同じように見てみましょうchannel.ThrowExceptionUseIsOneWay();。サービス ホストで例外が発生しますが、クライアント側では例外が発生せず、「操作が実行されました」と表示されます。チャネルは次回使用できなくなることを認識しておくことが重要です。

したがってIsOneWay=true、期待どおりに機能します-メッセージは一方向にのみ送信されます。メソッドからオブジェクトを返すことはできず (void が想定されます)、FaultContract を使用したり、サービスの起動後に InvalidOperationException を取得したりすることはできません。

2.Thread.Sleep()。次のテストは、での大規模な操作Thread.Sleep()です。 IService1に拡張されます

  [OperationContract]
  int ThreadSleep();

  [OperationContract(IsOneWay=true)]

Service1.cs の実現は5 秒間待機しています。

public int ThreadSleep()
{
    System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
    return 1;
}

public void ThreadSleepUseIsOneWay()
{
    System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
}

経過した呼び出し時間をカウントするためのクライアントの少しの変更

System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
//call methode
channel.ThreadSleep();
stopwatch.Stop();
Console.WriteLine(string.Format("Operation executed in {0} seconds", stopwatch.Elapsed.Seconds));
Console.ReadKey();

双方向メソッド を呼び出すThreadSleep()と、「7 秒で操作が実行されました」という結果が得られます (スレッドのスリープに 5 秒 + チャネルの初期化に 2 秒)。

One way methodwith 呼び出しchannel.ThreadSleepUseIsOneWay()の結果は「0秒」です! サービスの応答を待つ必要はありません。

同じマシン上で信頼性が高く高速な接続であるNetNamedPipeBindingを使用することをお勧めします。

于 2012-01-24T22:11:29.977 に答える
2

詳細については、この投稿をご覧ください: http://kennyw.com/?p=130

また、信頼できるメッセージングが有効になっている場合、リクエストが正常に送信されたことが確認されると思いますが、上記の投稿にあるように、サービスはその時点で接続を終了します.

于 2008-12-06T23:38:50.013 に答える
1

私は同様の問題を抱えていました (一方向呼び出しが何もしないか、例外をスローします)。メソッドの引数を xml からオブジェクトに変換するデシリアライザーが例外を作成していることがわかりました。一方向の呼び出しだったため、サービス メソッドに到達せず、例外も返されませんでした。「一方向」を一時的に無効にするまでそれを検出しなかったため、例外がクライアントに伝播されました。

これが同様の状況にある他の誰かに役立つことを願っています。

于 2013-03-22T17:16:39.997 に答える
1

「通知が送信されたことを確認する」ことはできません...そして「メソッドを一方向に保つ」ことはできません。それはちょっと「OneWay」の意味に反します:)

メッセージを確実に送信したい場合は、TwoWay を実行しても問題ありません。ほとんどの場合、わずかなパフォーマンスの低下に気付かないでしょう。そして、サーバーとクライアントがあなたが言及したのと同じマシン上にある場合...パフォーマンスの低下にまったく気付かないでしょう。

于 2008-12-06T19:50:04.123 に答える
1

これは、netMsmqBinding を使用するのに適した場所かもしれません。キューは本質的に切断されているため、すべての MSMQ メッセージは本質的に一方向です。クライアントが netMsmq クライアントでメッセージをキューに入れると、安全にシャットダウンでき、サーバーは後でメッセージを取得して処理できます。

于 2009-01-31T19:43:23.407 に答える
0

私はティモシーに同意します。また、WCF サービスが着信メッセージのキューを保持していることも付け加えたいと思います。サービスがメッセージを受信するのと同じ速さで処理できない場合、そのキューがいっぱいになることがあります。受信キューがいっぱいになると、WCF は新しいメッセージを削除します。

ただし、一方向メッセージがドロップされた場合にクライアント側で何が起こるかはわかりません。例外/障害はスローされないと思いますが、確かなことはわかりません。

于 2009-01-03T21:54:45.000 に答える