WCF WebSocket不会在断开连接时关闭

时间:2019-07-02 07:41:47

标签: c# wcf

我正在尝试在C#中使用自托管的websocket。基本上,我当前的测试正在运行,但是当客户端关闭websocket时,代码仍在尝试发送数据。 我想念什么吗?是否有更好的(内置)方法来处理websocket?

(我正在使用.Net Framework 4.8)

using System;
using System.Net.WebSockets;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Text;
using System.Threading.Tasks;

namespace WebSocketTest
{
    [ServiceContract]
    public interface ITestWebSocketCallback
    {
        [OperationContract(IsOneWay = true, Action = "*")]
        Task SendResult(Message msg);
    }

    [ServiceContract(CallbackContract = typeof(ITestWebSocketCallback))]
    public interface ITestWebSocket
    {

        [OperationContract(IsOneWay = true, Action = "*")]
        Task StartSending(Message msg);
    }

    public class TestWebSocket : ITestWebSocket
    {
        public async Task StartSending(Message msg)
        {
            Console.WriteLine("Started sending");
            var callback = OperationContext.Current.GetCallbackChannel<ITestWebSocketCallback>();
            try
            {
                var random = new Random();
                var result = 100.00;

                while (((IChannel)callback).State == CommunicationState.Opened)
                {
                    await callback.SendResult(CreateMessage($"{result}"));
                    result += random.NextDouble();
                    await Task.Delay(1000);
                }
                Console.WriteLine("Channel closed");
            }
            catch (WebSocketException wse)
            {
                Console.WriteLine($"WebSocketException: {wse.Message}");
            }
            catch (Exception e)
            {
                Console.WriteLine($"Exception: {e.Message}");
            }
            Console.WriteLine("Finished sending");
        }

        Message CreateMessage(string msgText)
        {
            var msg = ByteStreamMessage.CreateMessage(new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgText)));
            msg.Properties["WebSocketMessageProperty"] = new WebSocketMessageProperty
            {
                MessageType = WebSocketMessageType.Text
            };
            return msg;
        }
    }

    static class Program
    {
        static void Main(string[] args)
        {
            var baseAddress = new Uri("http://localhost:8080/TestWS");
            // Create the ServiceHost.
            var _host = new ServiceHost(typeof(TestWebSocket), baseAddress);

            //// Enable metadata publishing.
            var behaviour = new ServiceMetadataBehavior();
            behaviour.HttpGetEnabled = true;
            behaviour.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
            _host.Description.Behaviors.Add(behaviour);

            // Create WebSocket
            var binding = new CustomBinding();
            binding.Elements.Add(new ByteStreamMessageEncodingBindingElement());
            var transport = new HttpTransportBindingElement();
            transport.WebSocketSettings.TransportUsage = WebSocketTransportUsage.Always;
            transport.WebSocketSettings.CreateNotificationOnConnection = true;
            binding.Elements.Add(transport);
            _host.AddServiceEndpoint(typeof(ITestWebSocket), binding, "");

            // Open the ServiceHost to start listening for messages.
            Console.WriteLine("Opening websocket...");
            try
            {
                _host.Open();
                Console.WriteLine("Opened!");
                Console.WriteLine(baseAddress);
            }
            catch (Exception e)
            {
                Console.WriteLine($"Cannot open: {e.Message}");
                throw;
            }

            Console.WriteLine("Press any key to exit");
            Console.ReadKey();
        }
    }
}

除了输出类似于:

Started sending
Channel closed
Finished sending

但是我得到了

Started sending
WebSocketException
Finished sending

1 个答案:

答案 0 :(得分:0)

据我所知,这是不可能的。如官方文档中所述(由于WCF通过使用websocket协议实现双工通信,因此双工通信等于websocket)。

  

双工模型不会自动检测服务或客户端的时间   关闭其频道。因此,如果客户端意外终止,则默认情况下   不会通知该服务,或者如果服务意外   终止,不会通知客户端。如果您使用的服务   断开连接后,将引发CommunicationException异常。   客户端和服务可以实现自己的协议以通知每个   其他,如果他们选择的话。有关错误处理的更多信息,请参见   WCF错误处理

https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/duplex-services
在我看来,我们可以发送一个心跳包来证明客户端处于活动状态,或者可以定义和实现另一个服务合同,或者在OperationContext等下面使用。

OperationContext.Current.Channel.Faulted += delegate
{
    Console.WriteLine("");
};