次のような wcf にコールバック サービスがあります。
[ServiceContract(CallbackContract = typeof(IMyCallbacks), Namespace = "MyNamespace")]
public interface IMyService
{
[OperationContract]
bool subscribe();
[OperationContract]
bool unsubscribe();
}
public interface IMyCallbacks
{
[OperationContract(IsOneWay=true)]
void onNewCallback(int iValue);
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Multiple)]
public class MyService : IMyService
{
Action<int> DelegateOnNewCallback { get; set; }
public bool subscribe()
{
try
{
var wClient = OperationContext.Current.GetCallbackChannel<IMyCallbacks>();
DelegateOnNewCallback += wClient.onNewCallback;
}
catch (Exception iEx)
{
Console.Writeline(iEx.Message);
return false;
}
return true;
}
public bool unsubscribe()
{
try
{
var wClient = OperationContext.Current.GetCallbackChannel<IMyCallbacks>();
DelegateOnNewCallback -= wClient.onNewCallback;
}
catch (Exception iEx)
{
Console.Writeline(iEx.Message);
return false;
}
return true;
}
// This function is called really often
public void CallingFunction(int iValue)
{
try
{
DelegateOnNewCallback(iValue);
}
catch (Exception ex)
{
Console.Writeline(ex.Message);
}
}
}
クライアント側では、ロード時にコールバックをサブスクライブし、受け取った値を出力します。クライアントが閉じられたら、unsubscribe メソッドを呼び出します。Service はクライアントから独立しており、プロセスで破棄されることはありません。
クライアント プロセスが破棄され、unsubscribe メソッドが呼び出されない場合に問題が発生します。Wcf チャネルが障害状態にあるため、後続のすべてのクライアントはコールバックを受信しません。CallingFunction が呼び出されるたびに、例外が発生します。
The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it has been Aborted.
unsubscribe が適切に呼び出されなかったため、 DelegateOnNewCallback が、現在存在しない破棄されたクライアントのメソッドを呼び出そうとしているためだと思います。その特定のケースでは、Try/Catch を介して例外を受け取ることが期待されますが、サービスが障害状態になることは期待できません。
私が望む動作は、CallingFunction が呼び出されたときに、DelegateOnNewCallback に含まれるすべてのメソッドを呼び出そうとし、メソッドが存在しなくなった場合は、黙ってリストから削除し、後続のメソッドの呼び出しを続行することです。
どうすればこれを達成できますか?