Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

.NET

Socket Support in Silverlight 2: Part II


Dan Wahlin (Microsoft Most Valuable Professional for ASP.NET and XML Web Services) is a .NET development instructor and architecture consultant at Interface Technical Training. Dan founded the XML for ASP.NET Developers site, which focuses on using ASP.NET, XML, Silverlight, AJAX, and Web Services on .NET and runs smartwebcontrols.com. He’s also on the INETA Speaker's Bureau and speaks at several conferences. Dan has co-authored/authored several different books on .NET, including ASP.NET 2.0 MVP Hacks, Professional ASP.NET AJAX, XML for ASP.NET Developers and is currently working on a new book on Silverlight 2. Dan blogs at http://weblogs.asp.net/dwahlin.


Sockets provide a way to push data from a server to a Silverlight 2 client in ways that aren't possible with AJAX. This provides an interesting scenario for applications that need multiple clients to stay in-sync and up-to-date. In Part I of this article series, I walked through the process of writing code for creating a socket server that could listen for client connections. The server handled sending team and score data to Silverlight clients that could display the data using animations and other Silverlight specific features. In this article, I discuss how classes in the System.Net.Sockets namespace available in Silverlight 2 can be used to connect to a server and receive data that can be displayed in the user interface.

Creating a Silverlight Socket Client

Silverlight 2 provides a Socket class located in the System.Net.Sockets namespace (a Silverlight namespace, not the standard .NET Framework namespace) that can be used to connect a client to a server to send and receive data. The Socket class works in conjunction with a SocketAsyncEventArgs class to connect and send/receive data. SocketAsyncEventArgs is used to define asynchronous callback methods and pass user state between those methods such as the Socket object that originally connected to the server.

An example of using the Socket and SocketAsyncEventArgs classes together to connect to a server is in Listing One.

private void Page_Loaded(object sender, RoutedEventArgs e)
{
    DnsEndPoint endPoint = 
      new DnsEndPoint(Application.Current.Host.Source.DnsSafeHost, 4530);
    Socket socket = new Socket(AddressFamily.InterNetwork, 
      SocketType.Stream, ProtocolType.Tcp);

    SocketAsyncEventArgs args = new SocketAsyncEventArgs();
    args.UserToken = socket;
    args.RemoteEndPoint = endPoint;
    args.Completed += 
      new EventHandler<SocketAsyncEventArgs>(OnSocketConnectCompleted);
    socket.ConnectAsync(args);   
}
Listing One: Using the Socket and SocketAsyncEventArgs classes to connect to a socket server.

The code in Listing One first identifies the application's host server along with a port of 4530 (Silverlight can only connect to servers on a port between 4502 and 4532). A Socket object capable of communicating using the TCP protocol is then created. Once the Socket object is created, a SocketAsyncEventArgs object is instantiated and the socket object is assigned to the UserToken property so that it is passed through to other methods. The target endpoint of the server is set using the RemoteEndPoint property and the argument object's Completed event is hooked to an asynchronous callback method named OnSocketConnectCompleted. Once these objects are created and ready to use, the Socket object's ConnectAsync() method is called which accepts the SocketAsyncEventArgs object as a parameter.

When the client is connected to the server the OnSocketConnectCompleted() method in Listing Two is called which creates a buffer to hold data received from the server and rewires the SocketAsyncEventArgs's Completed event to a different callback method named OnSocketReceive which is used to received data sent from the server.

private void OnSocketConnectCompleted(object sender, SocketAsyncEventArgs e)
{
    byte[] response = new byte[1024];
    e.SetBuffer(response, 0, response.Length);
    e.Completed -= 
      new EventHandler<SocketAsyncEventArgs>(OnSocketConnectCompleted);
    e.Completed += new EventHandler<SocketAsyncEventArgs>(OnSocketReceive);
    Socket socket = (Socket)e.UserToken;
    socket.ReceiveAsync(e);
}
Listing Two: Once a Silverlight client is connected to the server a callback method is called to begin the process of exchanging data between the client and server.

Once the Silverlight client has connected to the server, the Socket object's ReceiveAsync() method is called to begin the process of accepting data from the server. As data is received the OnSocketReceive() method is called which handles deserializing XML data returned from the server into CLR objects that can be used in the Silverlight client. The OnSocketReceive() method is in Listing Three.

private void OnSocketReceive(object sender, SocketAsyncEventArgs e)
{
    StringReader sr = null;
    try
    {
        string data = Encoding.UTF8.GetString(e.Buffer, e.Offset, 
         e.BytesTransferred);
        sr = new StringReader(data);
        //Get initial team data
        if (_Teams == null && data.Contains("Teams"))
        {
            XmlSerializer xs = new XmlSerializer(typeof(Teams));
            _Teams = (Teams)xs.Deserialize(sr);
            this.Dispatcher.BeginInvoke(UpdateBoard);
        }
        //Get updated score data
        if (data.Contains("ScoreData"))
        {
            XmlSerializer xs = new XmlSerializer(typeof(ScoreData));
            ScoreData scoreData = (ScoreData)xs.Deserialize(sr);
            ScoreDataHandler handler = new ScoreDataHandler(UpdateScoreData);
            this.Dispatcher.BeginInvoke(handler, new object[] { scoreData });
        }
    }
    catch { }
    finally
    {
        if (sr != null) sr.Close();
    }
    //Prepare to receive more data
    Socket socket = (Socket)e.UserToken;
    socket.ReceiveAsync(e);
}
Listing Three:Receiving data in a Silverlight client sent from a server using a socket.

Silverlight 2 provides a robust set of choices for working with data returned from a socket, service or REST call. In this application the deserialization process is handled by the XmlSerializer class which keeps the code nice and clean. This class has been around since version 1.0 of the .NET framework and is now available in Silverlight's System.Xml.Serialization namespace. The XmlSerializer is used to deserialize data received from the server to Teams and ScoreData objects, respectively. The Teams and ScoreData classes can be created by hand within the Silverlight project or created using .NET's xsd.exe tool which can convert XML schemas into C# or VB.NET code. Additional details about using xsd.exe are available in the .NET framework SDK. In cases where more flexibility is needed the XmlReader class (located in the System.Xml namespace) can be used or the LINQ to XML technology (System.Xml.Linq namespace) available in Silverlight.

Looking through the code in Listing Three you'll see that data is routed back to the UI thread by using the Dispatcher class's BeginInvoke() method. If you've worked with Windows Forms before then this should look somewhat familiar since data retrieved on non-GUI threads needs to be re-routed back to the GUI thread so that controls can be updated properly. The Silverlight Dispatcher class provides the functionality to route data between threads.

That's all there is to work with sockets in a Silverlight client. There's certainly some initial work involved, but many of the complexities are hidden away in the Socket and SocketAsyncEventArgs classes which both minimize the need to work with threads directly. The previous article showed what the client interface looks like as data is updated but here it is one more time (see Figure 1).

[Click image to view at full size]
Figure 1: A Silverlight 2 interface that has data pushed to it from a socket server.

Summary

Sockets provide an interesting way to push data from a server to a client in ways that aren't possible using technologies such as AJAX. By using sockets, one or more clients can be kept up-to-date with data that is pushed from a server as it changes. This allows the client to stay up-to-date without involving any polling operations to the server to see if data has changed.

All of the code for the Silverlight socket application discussed in this two-part article series can be downloaded here. Additional information about building Silverlight applications including videos tutorials can be found on my blog.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.