コールバックを機能させようとしているWCFサービスがあります。
Interfaceクラスは次のようになります。
[ServiceContract(
SessionMode = SessionMode.Required,
CallbackContract = typeof(IPredatorEngineCallback))]
public interface IMyApplication
{
[OperationContract]
Boolean DoSomething(string mystring);
[OperationContract]
Boolean SubscribeToEvent();
}
public interface IMyApplicationCallback
{
[OperationContract (IsOneWay = true)]
void EventRaised(EventMessage myEventMessage)
}
EventMessageは、サーバーとクライアントが共有する通信ライブラリにあるクラスです。
このインターフェースの実装は次のようになります。
[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple)]
public class MyApplication : IMyApplication
{
private List<IMyApplicationCallback> CallbackList = new List<IMyApplicationCallback>;
public Boolean DoSomething(string mystring)
{
// Do stuff
// Now Raise an event
PublishEvent();
return true;
}
public Boolean SubscribeToEvent()
{
IMyApplicationCallback IMAC = OperationContext.Current.GetCallbackChannel<IMyApplicationCallback>();
if (!Callbacklist.Contains(IMAC)
Callbacklist.Add(IMAC);
}
private void PublishEvent()
{
EventMessage myEM = new EventMessage();
// Populate myEM.Fields
Callbacklist.ForEach(delegate(IMyApplicationCallback callback)
{ callback.EventRaised(myEM); });
}
}
アイデアは、クライアントがイベントの受信をサブスクライブすることを選択できるということです。
アプリを段階的に構築し、コールバックを実装する直前に、サービスは正常に機能します。DoSomething()に対して行われた呼び出しは、想定されていることを実行し、ほとんどすぐに戻ります。
CallBacksを実装したので、DoSomethingのRaiseEvents()行をコメントアウトすると、すぐに返されます。
クライアントコードは、最初にSubscribeToEvent()を呼び出し、次にDoSomething()を2回呼び出します。
コメントを外してデバッガーを実行すると、DoSomethingがすぐに正常に終了することがわかります。遅延はありません。クライアントとWCFサービスの両方をVS2010と同じマシンで実行しています。DoSomething()の最後の}まで続きます。
ただし、クライアントのコールバック関数は呼び出されません。1分後、ようやく呼び出され、元の呼び出しがタイムアウトしたことを示すエラーメッセージも表示されました。そこで、app.configを10秒に短縮するように変更しましたが、エラーメッセージは次のとおりです。
"This request operation sent to http://localhost:8732/Design_Time_Addresses/MyApplication/MyAppication did not receive a reply in the configured timeout (00:00:09.987997). The time allotted to this operation may have been a portion of a longer timeout..."
したがって、何かが最初の呼び出しの戻りをブロックしているように見えます。しかし、最終的にそこに到達するため、イベントが発生しました。これはロック/同時実行モードに関係していると思いますが、解決策がないことを認めます。
クライアント側では、サービス参照を追加して生成されたプロキシコードを使用しました。
サーバー側のapp.config(関連部分のみ):
</configuration>
クライアント側のApp.config:
<configuration>
<system.serviceModel>
<bindings>
<wsDualHttpBinding>
<binding name="WSDualHttpBinding_IPredatorEngine" closeTimeout="00:00:10"
openTimeout="00:00:10" receiveTimeout="00:10:00" sendTimeout="00:00:10"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" />
<security mode="Message">
<message clientCredentialType="Windows" negotiateServiceCredential="true"
algorithmSuite="Default" />
</security>
</binding>
</wsDualHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8732/Design_Time_Addresses/MyApplication/MyApplication/"
binding="wsDualHttpBinding" bindingConfiguration="WSDualHttpBinding_IMyApplication"
contract="MyApplication.IMyApplication" name="WSDualHttpBinding_IMyApplication">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
私は何かが正しく構成されていないと思います。誰かがそれを見つけることができますか?