WCF
既存のアプリケーションに組み合わせる必要のあるサービスがあります。
サービスのインターフェース:
[ServiceContract(CallbackContract = typeof(IClientCallback))]
public interface IExecutionService
{
[OperationContract]
ExecutionStatus Execute(string path);
[OperationContract]
ExecutionStatus Abort();
}
そしてコールバック:
[ServiceContract]
public interface IClientCallback
{
[OperationContract(IsOneWay = false)]
string GetUserInput(string message, string information, bool isPause);
[OperationContract(IsOneWay = true)]
void OutputAvailable(OutputAvailableEventArgs args);
[OperationContract(IsOneWay = true)]
void ResultAvailable(ResultAvailableEventArgs args);
[OperationContract(IsOneWay = true)]
void ExecutionStarted(ExecutionStartedEventArgs args);
[OperationContract(IsOneWay = true)]
void ExecutionEnded(ExecutionEndedEventArgs args);
}
報告するものがある場合、サービスはいくつかの作業と報告を実行しています。ArgsクラスはDataContract
、名前空間としてマークされています。.Netネイティブタイプ(、、)が含まれてint
いstring
ますDateTime
。
テストアプリケーションを作成しましたが、すべてがうまく機能しています(サービスの実行を要求してから、ExecutionStarted
約1秒と呼ばれるまでの時間)。
既存のアプリケーションでクライアントを作成する場合、2つの問題があります。
Execute()
遅さ-からまで約1分ExecutionStarted()
。- 最後の呼び出し
ExecutionEnded
---ただ起こりません。どうなりますか?代わりに最後のOutputAvailable
呼び出しが発生します。デバッグ中に、サービスがExecutionEnded
メソッドを呼び出しているのがわかりますが、クライアント側で呼び出されるのはOutputAvailable
(finishメソッドの代わりではなく、以前にのみ呼び出されるべきでした)です。
テストクライアントと実際のアプリケーションで同じテストを使用しています。
役立つかもしれないいくつかのコード、私は願っています:
サービス:
クラス宣言:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class ExecutionService : IExecutionService
public ExecutionStatus Execute(string path)
{
lock (locker)
{
var tempClient = OperationContext.Current.GetCallbackChannel<IClientCallback>();
if (client == null)
client = tempClient;
else if (client != null && client != tempClient)
{
throw new FaultException(new FaultReason("Execution Service is busy processing a request."));
}
else if (tempClient == null)
throw new FaultException(new FaultReason("No client found, execution is aborted."));
Log.InfoFormat("client: "+ DateTime.Now);
Log.InfoFormat(client == null ? "null" : client.ToString());
}
((IContextChannel)client).OperationTimeout = new TimeSpan(0,3,0);
Task<ExecutionStatus> executionTask = Task.Factory.StartNew(() => HandleExecution(path));
return executionTask.Result;
}
(一度に1つのクライアントしかないことを確認します。サービスのメソッド中にコールバックを使用できるように、再入可能モードが必要です。)
クライアント: サービスへの接続を作成します。
var myBinding = new WSDualHttpBinding();
var myEndpoint = new EndpointAddress("http://localhost:3050/ExecutionService");
var myChannelFactory = new DuplexChannelFactory<IExecutionService>(this, myBinding, myEndpoint);
service = myChannelFactory.CreateChannel();
var executionStatus = service.Execute(@"C:\Users\nosh\Desktop\launcher.py");
必要に応じて、さらにコードを公開します。
もう1つの問題は、実際のアプリでは次のようになることです。
A first chance exception of type 'System.TimeoutException' occurred in System.ServiceModel.dll
A first chance exception of type 'System.TimeoutException' occurred in mscorlib.dll
'execute'メソッドが戻る直前、および後で次のようになります。
A first chance exception of type 'System.Runtime.Serialization.SerializationException' occurred in System.Runtime.Serialization.dll
A first chance exception of type 'System.ServiceModel.Dispatcher.NetDispatcherFaultException' occurred in System.ServiceModel.dll
A first chance exception of type 'System.ServiceModel.Dispatcher.NetDispatcherFaultException' occurred in System.ServiceModel.dll
A first chance exception of type 'System.ServiceModel.Dispatcher.NetDispatcherFaultException' occurred in System.ServiceModel.dll
A first chance exception of type 'System.ServiceModel.Dispatcher.NetDispatcherFaultException' occurred in System.ServiceModel.dll
これは私のテストアプリケーションでは発生しません。
ここで何が問題なのか分かりますか?
編集
私はそれを修正する方法ではなく、何が悪いのかを知っていると思います。問題は、私の実際のアプリがでWPF
あり、での動作にいくつかの問題があることWCF
です。に切り替えてみましたNetTcpBinding
が、うまくいきませんでした。他の提案をいただければ幸いです。
編集2
このWPF
問題については、コールバックの実装に以下を追加する必要があります。
[CallbackBehavior(UseSynchronizationContext = false)]
(ここで答えを提供してくれたIan Ringroseに感謝します。)
今でも応答しないクライアントに直面していますが、サービスへの接続がハングしません。もっと提案をいただければ幸いです。 WPF
編集3
これで、クライアントで呼び出されていないのは1つのメソッドだけになります。接続は有効であり(その後に他の呼び出しがあります)、メソッドは特別なことを何もしていません。