![](/img/trans.png)
[英]How to make client automatically detect if WCF service is down or lost connection
[英]How can WCF service detect client disconnection
我有以下完整的程序(可以復制粘貼,構建並運行。您可能需要添加一些引用)。 該程序的目的是使服務在響應之前檢測到(例如,通過某種事件處理接收到某種形式的SocketException
或IOException
或在代碼中通過某些事件處理所嘗試的)已斷開連接的客戶端(從Web瀏覽器測試/測試)已斷開連接已完全交付(請參見Talk(string animal)
方法中的return
語句)。 為了重現此問題,有一個可配置的參數(請參閱new AnimalTalkService(3)
),該參數指示服務響應給定請求將花費多長時間。 在此時間范圍內,我可以關閉瀏覽器以引發客戶端斷開連接事件(請參閱類ClientConnectionTracker
方法ClientDisconnected()
)。 我無法將任何異常拋出到服務的實現中,也無法觸發Closed
和Faulted
事件。 有人會對如何實現(實現)達到預期的效果有想法嗎?
// Code:
using System;
using System.Net;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Web;
using System.Threading;
namespace TestClientDisconnect
{
class ClientConnectionTracker : IChannelInitializer
{
public void Initialize(IClientChannel channel)
{
channel.Closed += ClientDisconnected;
channel.Faulted += ClientDisconnected;
}
private void ClientDisconnected(object sender, EventArgs e)
{
Console.WriteLine("Client Disconnected");
throw new NotImplementedException();
}
}
class ClientConnectionTrackerEndpointBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.ChannelDispatcher.ChannelInitializers.Add(new ClientConnectionTracker());
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
[ServiceContract]
interface IAnimalTalkService
{
[OperationContract]
[WebInvoke(UriTemplate = "/{animal}", Method = "GET")]
string Talk(string animal);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
class AnimalTalkService : IAnimalTalkService
{
private int delayInSeconds;
public AnimalTalkService(int delayInSeconds = 0)
{
this.delayInSeconds = delayInSeconds;
}
public string Talk(string animal)
{
Console.WriteLine("Creating sentence for animal {0} ...", animal);
if (delayInSeconds > 0)
{
// Simulate heavy duty work:
Thread.Sleep(1000 * delayInSeconds);
}
switch(animal.ToLower())
{
case "sheep":
return "baa";
case "dog":
return "woof";
case "cat":
return "miao";
default:
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.NotFound;
return null;
}
}
}
class Program
{
static void Main(string[] args)
{
AnimalTalkService serviceInstance = new AnimalTalkService(3);
Uri address = new Uri("http://127.0.0.1:1234/");
WebServiceHost host = new WebServiceHost(serviceInstance, address);
WebHttpBinding binding = new WebHttpBinding();
ServiceEndpoint endPoint = host.AddServiceEndpoint(typeof(IAnimalTalkService), binding, "");
endPoint.EndpointBehaviors.Add(new WebHttpBehavior() { DefaultOutgoingResponseFormat = WebMessageFormat.Json });
endPoint.EndpointBehaviors.Add(new ClientConnectionTrackerEndpointBehavior());
host.Open();
Console.WriteLine("Service is running at {0}. Press Enter key to exit", host.BaseAddresses[0]);
Console.ReadLine();
}
}
}
提前致謝。
“斷開連接”一詞意味着一個會話,不是嗎?
我認為,最好的方法是使用一個顯式的會話ID(在這里我使用任意類型)來顯式創建和終止會話:
[ServiceContract]
public interface IWebService
{
[OperationContract]
SessionId BeginNewSession();
[OperationContract]
void DoSomething(SessionId id, ...);
[OperationContract]
void EndSession(SessionId id);
}
對於不支持傳輸級會話的HTTP協議,當然推薦這樣做。
在這種情況下,您可以編寫另一個類,該類將保留尚未關閉的過時會話。
如果使用支持傳輸級會話的綁定,則還有另一個選擇-設置會話綁定的服務實例管理(並使用相應的綁定),在服務類中實現IDisposable
接口,並將相關代碼放入Dispose()
方法:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class TheService : IService, IDisposable
{
...
public void Dispose()
{
// code of session termination
...
}
}
最后,您可以通過使用[OperationContract(IsTerminating = true)]
屬性標記顯式會話終止方法來組合這兩個選項:
[ServiceContract(..., SessionMode=SessionMode.Required)]
public interface IService
{
[OperationContract(IsTerminating = true)]
void Close();
...
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.