我正在尝试建立一个SOA,客户端可以在其中对服务器执行长时间运行的查询,并且服务器使用回调进行响应。
我希望能够检测到客户端是否断开连接(通过用户启动的关机,未处理的异常或网络连接丢失),以便服务器可以选择取消昂贵的请求。
我正在测试各种失败案例,但似乎无法启动某些事件处理程序。
经测试的失败案例:
请求后终止客户端进程。
使用CurrPorts之类的程序关闭TCP连接。
测试代码:
using System;
using System.ServiceModel;
using System.Threading;
namespace WCFICommunicationObjectExperiments
{
class Program
{
static void Main(string[] args)
{
var binding = new NetTcpBinding(SecurityMode.None);
var serviceHost = new ServiceHost(typeof (Server));
serviceHost.AddServiceEndpoint(typeof (IServer), binding, "net.tcp://localhost:5000/Server");
serviceHost.Open();
Console.WriteLine("Host is running, press <ENTER> to exit.");
Console.ReadLine();
}
}
[ServiceContract(CallbackContract = typeof(IClient))]
public interface IServer
{
[OperationContract]
void StartProcessing(string Query);
}
public interface IClient
{
[OperationContract]
void RecieveResults(string Results);
}
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Server : IServer
{
public void StartProcessing(string Query)
{
Thread.Sleep(5000);
//Callback Channel
var clientCallback = OperationContext.Current.GetCallbackChannel<IClient>();
var clientCallbackCommunicationObject = ((ICommunicationObject) clientCallback);
EventHandler faultedHandlerCallback = (o, s) => Console.WriteLine("Client Channel Faulted.");
EventHandler closedHandlerCallback = (o, s) => Console.WriteLine("Client Channel Closed.");
clientCallbackCommunicationObject.Faulted += faultedHandlerCallback;
clientCallbackCommunicationObject.Closed += closedHandlerCallback;
//Request Channel
var requestChannel = OperationContext.Current.Channel;
EventHandler faultedHandlerRequest = (o, s) => Console.WriteLine("Request Channel Faulted.");
EventHandler closedHandlerRequest = (o, s) => Console.WriteLine("Request Channel Closed.");
requestChannel.Faulted += faultedHandlerRequest;
requestChannel.Closed += closedHandlerRequest;
try
{
clientCallback.RecieveResults("42.");
}
catch (CommunicationObjectAbortedException ex)
{
Console.WriteLine("Client Aborted the connection");
}
catch (CommunicationObjectFaultedException ex)
{
Console.WriteLine("Client Died.");
}
clientCallbackCommunicationObject.Faulted -= faultedHandlerCallback;
clientCallbackCommunicationObject.Faulted -= closedHandlerCallback;
requestChannel.Faulted -= faultedHandlerRequest;
requestChannel.Closed -= closedHandlerRequest;
}
}
public class ClientToTestStates : IClient
{
private IServer m_Server;
private readonly ManualResetEvent m_ReceivedEvent = new ManualResetEvent(false);
private readonly ManualResetEvent m_ChannelFaulted = new ManualResetEvent(false);
private readonly ManualResetEvent m_ChannelClosed = new ManualResetEvent(false);
public ClientToTestStates()
{
var binding = new NetTcpBinding(SecurityMode.None);
var channelFactory = new DuplexChannelFactory<IServer>(this, binding, new EndpointAddress("net.tcp://localhost:5000/Server"));
m_Server = channelFactory.CreateChannel();
((ICommunicationObject)m_Server).Open();
((ICommunicationObject)m_Server).Faulted += ChannelFaulted;
((ICommunicationObject)m_Server).Closed += ChannelClosed;
m_Server.StartProcessing("What is the answer?");
WaitHandle.WaitAny(new WaitHandle[] {m_ReceivedEvent, m_ChannelFaulted, m_ChannelClosed});
}
void ChannelFaulted(object sender, EventArgs e)
{
m_ChannelFaulted.Set();
Console.WriteLine("Channel Faulted.");
}
void ChannelClosed(object sender, EventArgs e)
{
m_ChannelClosed.Set();
Console.WriteLine("Channel Closed.");
}
public void RecieveResults(string results)
{
m_ReceivedEvent.Set();
Console.WriteLine("Recieved Results {0}", results);
}
}
}
处理此类故障案例的最佳实践是什么?我希望能够使用基础的tcp连接来检测其中的某些内容。
最佳答案
Juval Lowy在他的“Programming WCF Services”一书中解释说WCF没有提供用于管理服务回调的机制,并且必须由服务和客户端显式管理。如果服务尝试调用已在客户端上关闭的回调,则将在服务 channel 上引发ObjectDisposedException。
他建议向服务契约(Contract)中添加Connect and Disconnect方法-由于必须在调用这些回调时将回调提供给服务,因此该服务可以管理客户端回调。然后,由客户端来确保当它不再希望从服务中接收回调时,它调用Disconnect,并且服务在向客户端调用回调时必须处理任何异常。
关于c# - 在WCF双工契约(Contract)中检测客户端死亡,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/1427926/