Using WebSocket in .NET 4.5 (Part 3)

Introduction

Part 1 gives an overview of the WebSocket protocol and .NET WebSocket support.Part 2 demonstrates how to use WebSocket in traditional ASP.NET and MVC 4 webapplications.

In this article, I will demonstrate how to use WCF to host a WebSocket service and writea client application. I will also show how to communicate with a WCF WebSocketservice usingJavaScript in a webpage.

  • WcfWSChat.zip is the sample code of the WCF WebSocket service with a WCF client application.
  • WcfWSChatForWeb.zip is the sample code of the WCF WebSocket service with a web page and JavaScript.

Preparation

To enable WebSocket on the server side, please refer to Part 1.

Host Service

In WCF 4.5, netHttpBinding and netHttpsBindinghave been re-implemented to support WebSocket. And to make a WCF service serve the client through WebSocket, we should set CallbackContract for theServiceContract attribute in the service interface declaration. For example:

[ServiceContract(CallbackContract = typeof(IWSChatCallback))]
public interface IWSChatService
{  
    [OperationContract(IsOneWay = true)]
    Task SendMessageToServer(string msg);
}

The SendMessageToServer method will be called by the client and themsg argument is the message sent by the user. So the server should implement this method to handle the msg received from the client.IsOneWay should be set to true for the OperationContract attribute because the client should not wait for the return value of the service method call in duplex communication. CallbackContractis bound to IWSChatCallback which is declared as below:

[ServiceContract]
interface IWSChatCallback
{   
    [OperationContract(IsOneWay = true)]
    Task SendMessageToClient(string msg);
} 


The SendMessageToClient method will be called by the server and the msgargument is the message sent by the server. So the client should implement this method to handle the msg received from the server. Again,IsOneWay should be set to true because the server should not wait for the return value of the callback method call in duplex communication.

Let’s simply implement IWSChatService as an echo server:

public class WSChatService : IWSChatService
{
    public async Task SendMessageToServer(string msg)
    {
        var callback = OperationContext.Current.GetCallbackChannel();
        if (((IChannel)callback).State == CommunicationState.Opened)
        {
            await callback.SendMessageToClient(
                string.Format("Got message {0} at {1}", 
                msg, DateTime.Now.ToLongTimeString()));
        }
    }
}

The service just decorates the message received from the client and calls SendMessageToClient to send the decorated message to the client.

Then we need to modify web.config to add a protocol mapping schema in the  tag like:

 
  
 

The default netHttpBinding and netHttpsBindingwill transfer data in Binary SOAP format. If you want to useText SOAP format, you could create a customized configuration and set messageEncodingto “Text” like:


  


  
    
  
 


OK. The WCF WebSocket service gets ready after I build it.

Client Application

To write a WCF client application, I create a console application and add the previous WCF service to Service References. Then I implement theIWSChatServiceCallback interface declared previously on the server:

internal class CallbackClient : IWSChatServiceCallback
{
    public void SendMessageToClient(string msg)
    {
        Console.WriteLine(msg);
    }
} 


In the SendMessageToClient method, I just display the message received from the server.

The program’s main function looks like:

class Program
{
    static void Main(string[] args)
    {
        var context = new InstanceContext(new CallbackClient());
        var client = new WSChatServiceClient(context);
        while (true)
        {
            Console.Write("Input (\"Exit\" to exit):");
            string input = Console.ReadLine();
            if (input.ToUpperInvariant() == "EXIT")
            {
                break;
            }
            client.SendMessageToServer(input);
            Thread.Sleep(500);
        }
        client.Close();
    }
} 

Don’t forget to modify the endpoint address in App.config to point to the correctmachine name, domain name, or IP address.

Again to emphasize, the client application can only work on Windows 8,Windows Server 2012, and above.

JavaScript in Web Page

By using netHttpBinding and netHttpsBinding, all data transferred in a WCF WebSocket connection is in SOAP format (Binary or Text). To communicate with the WCF WebSocket service with JavaScript code in the web page, I have to parse the SOAP by myself.

To avoid SOAP, I need to create and use a custom binding as below:


  
    
           
             
             
      
     
  


  

I use byteStreamMessageEncoding to specify the data should be transferred as byte stream instead of SOAP. In webSocketSettings,transportUsage is set to Alwaysto enable the WebSocket protocol regardless of the contract; createNotificationOnConnectionmust be set to “true” to notify the client when connection is established.

The service interface and implementation need to change as well. I modified IWSChatService and IWSChatCallback as below:

[ServiceContract(CallbackContract = typeof(IWSChatCallback))]
public interface IWSChatService
{
    [OperationContract(IsOneWay = true, Action = "*")]
    Task SendMessageToServer(Message msg);
}
[ServiceContract]
interface IWSChatCallback
{
    [OperationContract(IsOneWay = true, Action="*")]
    Task SendMessageToClient(Message msg);
} 

I change the type of the msg argument from string to Message(System.ServiceModel.Channels) which will wrap my UTF-8 encoded text.Then I re-implement IWSChatServiceas below:

public class WSChatService : IWSChatService
{
    public async Task SendMessageToServer(Message msg)
    {
        var callback = OperationContext.Current.GetCallbackChannel();
        if (msg.IsEmpty || ((IChannel)callback).State != CommunicationState.Opened)
        {
            return;
        }
        byte[] body = msg.GetBody();
        string msgTextFromClient = Encoding.UTF8.GetString(body);
        string msgTextToClient = string.Format(
            "Got message {0} at {1}",
            msgTextFromClient,
            DateTime.Now.ToLongTimeString());
        await callback.SendMessageToClient(
            CreateMessage(msgTextToClient));
    }
    private Message CreateMessage(string msgText)
    {
        Message msg = ByteStreamMessage.CreateMessage(
            new ArraySegment(Encoding.UTF8.GetBytes(msgText)));
        msg.Properties["WebSocketMessageProperty"] =
            new WebSocketMessageProperty 
            { MessageType = WebSocketMessageType.Text };
        return msg;
    }
} 

The client side need not implement IWSChatCallback. My JavaScript code is very similar to the example in Part 2:




    WebSocket Chat
    
    


    
    

(display)

Summary

Next in Part 4, I will demonstrate how to use Microsoft.WebSockets.dll.

Related Links

Using WebSocket in .NET 4.5:

  • Part 1: Overview on WebSocket protocol and .NET support
  • Part 2: Using WebSocket in Traditional ASP.NET and MVC 4
  • Part 3: Using WCF support for WebSocket 
  • Part 4: Using Microsoft.WebSockets.dll

你可能感兴趣的:(Web,Development,.NET,Development)