私はそれがなぜそうかもしれないのか分かりません。しかし、私は非同期呼び出しを使用する場合は、ブロックされませんと確信しています。その後のWCF呼び出しにより、原因不明のブロックが発生し、最終的にTimeoutExceptionが発生しますか?
ここでのシナリオでは、2つのWCFメソッド呼び出しがあります。最初の呼び出しでは、クライアントへのコールバック呼び出しが発生します(CallbackContract
を使用)。 2つ目は、通常のWCFメソッド呼び出し(コードを一切持たない空のメソッドでさえ)です。
メソッドの内容は重要ではありません、ここでは擬似コードのほんのいくつかの種類である:SecondMethod
を呼び出さずに
public void FirstMethod(){
//some logic here...
//here I use some Callback method to client side
clientCallbackInterface.SomeMethod();//commenting this out won't
//cause any blocking.
}
public void SecondMethod(){
//this is even empty
}
//call the 2 methods synchronously in a sequence
client.FirstMethod();
client.SecondMethod();
、それはうまく動作します。非同期呼び出しを使用している場合は、正常に動作します。また、(クライアントコールバックインターフェイスを使用して)コールをコメントアウトすると、うまく動作します。
例外TimeoutException
がスローされた時点で、方法SecondMethod
が実際に実行され、クライアントに応答する段階にあることが示されます。
ServiceBehaviorは、InstanceContextMode
がPerSession
、ConcurrencyMode
がMultiple
です。
私はここで誰かがこれを経験し、この問題の背後にある原因を理解してくれることを願っています。
UPDATE:
- 私はちょうど代わり
Single
からConcurrencyMode
を設定することで、新しいものを試してみたし、それもうまく実行します。ですから、ConcurrencyMode
がMultiple
の場合、それをうまく動作させる方法をもっと知りたいですか?
UPDATE:
私はここで間違っているかについて、本当に困惑している、実際にも、CallbackBehavior
を使用して、それは単にMultiple
のConcurrencyMode
と正常に動作しないいくつかの古いコードがあります。私のコードはCallbackBehavior
を必要とし、2つの方法を実行する2回目に失敗しました。ここで私は投稿できる最小のコードは、私はそれを試してみたされ、メソッドの内容は本当に重要ではありません、それだけで空にすることができます:
//the service interface
[ServiceContract(CallbackContract = typeof(IMyClient), SessionMode = SessionMode.Allowed)]
public interface IMyService
{
bool MyMethod();
}
//the client callback interface
public interface IMyClient
{
[OperationContract(IsOneWay = true)]
void OnSomething(SomeEventArgs e);
}
//the service class
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = false)]
public class MyService : IMyService
{
static Dictionary<ClientInfo, IMyClient> clients;
static Dictionary<ClientInfo, IMyClient> Clients
{
get
{
if (clients == null)
clients = new Dictionary<ClientInfo, IMyClient>();
return clients;
}
}
static void raiseEvents(Action<IMyClient> raiser, params Guid[] toClients)
{
if (raiser == null)
throw new ArgumentNullException("raiser cannot be null.");
System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(o => {
lock (clients)
{
//ClientInfo is just some class holding some info about
//the client such as its ClientGuid
Func<KeyValuePair<ClientInfo, IMyClient>, bool> filter = c => toClients.Length == 0 || toClients.Any(e => e == c.Key.ClientGuid);
foreach (var client in Clients.Where(filter).Select(e => e.Value))
{
raiser(client);
}
}
}));
}
public bool MyMethod(){
//do nothing before trying to trigger some callback to the client
raiseEvents(e => e.OnSomething(new SomeEventArgs()));
return true;
}
}
実際には上記のraiseEvents
方法は、(私は古いコードを踏襲するものです古いコードと私は書いている1間
static void raiseEvents(Action<IMyClient> raiser, params Guid[] toClients)
{
if (raiser == null)
throw new ArgumentNullException("raiser cannot be null.");
Func<KeyValuePair<ClientInfo, IPosClient>, bool> filter = c => toClients.Length == 0 || toClients.Any(e => e == c.Key.ClientGuid);
foreach (var client in Clients.Where(filter).Select(e => e.Value))
{
Task.Run(() => raiser(client));
}
}
一つの可能な差が設定している:私はそれが)動作しません。また、(このような非常に簡単になりますし、以前のように、)だけで正常に動作している述べたようにこの問題につながる可能性はあまりありません。実際に私はできるだけ多くの構成を複製しようとしました(約<behaviors>
)。
最初に説明したように、ここには2つの方法が含まれます。しかし、今回はコードのように1つのメソッドしかありません。最初はOKと呼ばれ、次回はUIをフリーズします(デッドロックのように)。あなたは(サービスの追加リファレンス・ウィザードによって自動生成された)クライアントプロキシクラスを持っているときにそれを呼び出すと、ただ単純です:
実際に//this is put in some Execute method of some Command (in WPF)
myServiceClient.MyMethod();
私は仕事-の周りにすることができ、この問題MyMethod
のasync
バージョンを使用しますか、単純にその呼び出しをスレッドに入れますが、古いコードではそれを行う必要はなく、なぜ初めて動作するのか不思議ですが、次回は凍結(TimeoutException
まで)を続けます。
クライアントアプリケーションの性質は何ですか? WPF/WinFormsまたはいくつかのWebページ?あなたはどのようにクライアント側でチャネル/プロキシを取得するのですか? –
@IgorLabutinクライアントアプリケーションはWPFアプリケーションであり、サービスのメソッドにアクセス/呼び出しするためにクライアントのクラスを生成するために、サービス参照の追加ウィザードを使用します。ご回答いただきありがとうございます。この問題を解決するためのご意見がありましたら幸いです。 – Hopeless
こちら(最後はこちら):http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,b891610a-6b78-4b54-b9a6-4ec81c82b7c0.aspxほとんどの場合、WPFアプリケーションのUIスレッドから呼び出され、コールバックはUIスレッドにもディスパッチされます。そのコールバックオブジェクトを[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant、UseSynchronizationContext = false)]を使用してデコレートしてみてください。 – Evk