我正在做一些WCF实验,以了解我可以使用会话,回调和TPL运行多远。其中一个实验有奇怪的结果...... 该服务使用双向绑定(NetTcpBinding)实现,并实现通知 作为回调。 预期的行为应该是:
该服务需要一个会话,InstanceContext是PerSession,并发模式是Single。 在这种情况下,我知道,在回调的上下文中,我无法以同步方式调用任何服务方法(在同一客户端上),因此代码可以是:
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(INotificationCallback))]
public interface INotificationService
{
[OperationContract]
int Do(int value);
[OperationContract]
int ReDo(int value);
}
public interface INotificationCallback
{
[OperationContract(IsOneWay = true)]
void Notify(int value);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Single)]
public class NotificationService : INotificationService
{
public int Do(int value)
{
var notificationCallback = OperationContext.Current.GetCallbackChannel<INotificationCallback>();
//Task.Run(() => notificationCallback.Notify(value * 2));
notificationCallback.Notify(value * 2);
Thread.Sleep(1000);
return value * 2;
}
public int ReDo(int value)
{
return value + 1;
}
}
在客户端上实现回调接口:
class CallbackInstance : INotificationServiceCallback
{
public NotificationServiceClient Client { get; set; }
#region Implementation of INotificationServiceCallback
public void Notify(int value)
{
Console.WriteLine("Notified: {0}", value);
Task<int> task = Client.ReDoAsync(value);
task.ContinueWith(t => Console.WriteLine("In Notify - ReDo({0}): {1}", value, t.Result));
}
#endregion
}
运行所有代码的主要方法:
static void Main(string[] args)
{
CallbackInstance callback = new CallbackInstance();
NotificationServiceClient client = new NotificationServiceClient(new InstanceContext(callback));
callback.Client = client;
int result = client.Do(10);
Console.WriteLine("Do({0}): {1}", 10, result);
Console.ReadLine();
}
在我认识的Notify方法实现中的行:
Task<int> task = Client.ReDoAsync(value);
task.ContinueWith(t => Console.WriteLine("In Notify - ReDo({0}): {1}", value, t.Result));
应该打破死锁但是......不,当调用ReDoAsync时会抛出异常,说“此操作会死锁,因为直到 当前消息完成处理...“。是的,亲爱的,我知道。事实上,我想以异步的方式回拨服务以绕过问题, 它不起作用。
但让我疯狂的是,改变一点代码使它像魅力一样工作;而不是我试过的ReDoAsync调用:
Task<int> task = Task.Run(() => Client.ReDo(value));
它的工作原理! 所以问题是:客户端方法的异步版本是否应该使调用与有效的调用相同或类似? 如果没有,那么客户端方法的Async版本究竟是什么呢?
感谢。