(X) Hide this
    • Login
    • Join
      • Generate New Image
        By clicking 'Register' you accept the terms of use .

The duplex story: looking at duplex communication in Silverlight - Part 3: Using Net.Tcp

(1 votes)
Gill Cleeren
>
Gill Cleeren
Joined Apr 02, 2010
Articles:   57
Comments:   6
More Articles
3 comments   /   posted on Jul 27, 2010
Categories:   Data Access , General

This article is compatible with the latest version of Silverlight.

This article is Part 3 of the series The Duplex Story in Silverlight.

In part 2, we looked at sockets. Using pure TCP for their communication, sockets make real duplexing possible: both sides of the communication channel can initiate communication. The server as well as the client can push data to the other side. There is no need to first have a request from the client to the server (which is the case with traditional HTTP).

While sockets are extremely fast, there’s a downside to that story as well: sockets in Silverlight only work on port numbers between 4502 and 4534. Therefore, sockets are great for intranet solutions but not for internet solutions. Also, we saw that working with sockets required an extensive amount of manual coding: there’s no support for WCF, so no proxies or whatever can be used in this scenario.

In this third and final part, we are going to look at the net.tcp binding. This binding was added to the Silverlight with the release of version 4. The great thing about this binding is that it combines some advantages of the polling duplex binding with sockets. In this article, we will recreate the sockets example from part 2, but now using net.tcp. The code can be downloaded here.

Before we dive into the code, we first need to perform some setup with our machine to support this binding.

  • In your Windows Features, make sure that Windows Communication Foundation Non-HTTP Activation is installed. If not, have Windows install this feature.
  • Make sure that the Net.Tcp Listener adapter service is running. From Control Panel à View Local Services, search for Net.Tcp Listener and make sure that the service is started.
  • Open IIS and create a new application (I’ve created the application StockService under the Default Web Site).
     
  • Once the application is created, we can configure it to use Net.Tcp. Right-click on Default Web Site and add the net.tcp binding. For the binding information, enter 4502:*.
  • Now, right-click on the StockService à Manage Application à Advanced Settings. In the dialog that appears, add net.tcp after http (which should be there already) in the Enabled Protocols field.
  • Go to the root folder of your server (typically “C:\inetpub\wwwroot”). In there, add a clientaccesspolicy.xml. If you omit adding this XML file there, all requests will fail with a security exception because of cross domain restrictions.

    The content of this file is as follows:

    <?xml version="1.0" encoding="utf-8"?>
    <access-policy>
      <cross-domain-access>
        <policy>
          <allow-from http-request-headers="*"> 
            <domain uri="*" />
          </allow-from>
          <grant-to>
            <socket-resource port="4502-4534" protocol="tcp" />
          </grant-to>
        </policy>
      </cross-domain-access>
    </access-policy>
  • Finally, we of course have to tell Visual Studio that it has to use this IIS folder to host the service we are about to create. In your solution, in the Properties window of the web project, enter the URL of the application (here: http://localhost/StockService).

With these steps completed, your system should be OK to use the net.tcp binding. Let’s now take a look at the net.tcp binding itself!

Advantages of using net.tcp

As already mentioned net.tcp combines advantages of both polling duplex and sockets. Its programming model is, just like polling duplex, based on WCF. That means that we can take advantage of automatic proxy generation inside Visual Studio and will have full IntelliSense with our client-side coding. On the other hand, it’s built on top of TCP. If you have read part 2, you’ll know that TCP stands for the best performance. And indeed, net.tcp has the same great performance. Here you can find a comparison graph between polling duplex and net.tcp. Some of the most striking conclusions are the following:

  • Throughput of net.tcp on a worker thread of a Silverlight 4 application is 870x times faster than polling duplex.
  • Throughput of net.tcp on a UI thread is 5.5x faster than polling duplex.
  • This results is a far better scalability with the same hardware: up to 5x more clients can be connected at the same time with the server when using net.tcp.

On the other hand, again being based on TCP, net.tcp has the same port restrictions (4502-4534), making it a good intranet solution but not an internet solution.

Server-side code

With the entire configuration done, let’s write some code and let’s begin with the server-side code.

The service code is very similar to the service we wrote with the Http Polling Duplex. It defines a CallbackContract which is used from the server code to access the client instances. The operations are marked with the IsOneWay attribute to notify that there should be no waiting for the service response. For more information, refer to part 1.

The code below shows the service contract.

[ServiceContract(Namespace = "Silverlight", 
    CallbackContract = typeof(IStockServiceClient))]
public interface IStockService
{
    [OperationContract(IsOneWay = true)]
    void Connect(string stockSymbol);
}
 
[ServiceContract]
public interface IStockServiceClient
{
    [OperationContract(IsOneWay = true)]
    void SendUpdate(Update update);
}

The service implementation code is again similar to the duplex binding. We use the GetCallbackChannel() on the OperationContext to get an instance of the client callback contract. This can then be stored in a list that we loop over when updates need to be sent to the client. Below is the relevant part of the service implementation.

public void Connect(string stockSymbol)
{
    client = OperationContext.Current.GetCallbackChannel<IStockServiceClient>();
    updateTimer = new Timer(new TimerCallback(TimerTick), null, 500, 5000);
}
 
void TimerTick(object state)
{
    if (client != null)
    {
        try
        {
            RefreshUpdate();
            client.SendUpdate(update);
        }
        catch (Exception)
        {
            client = null;
            updateTimer.Dispose();
        }
    }
}

One aspect that is different from the duplex binding is the configuration code. In the web.config, you can notice that the endpoint is now configured to be used with the nettcpbinding.

<?xml version="1.0"?>
<configuration>
  <system.serviceModel>
    <extensions>
      <bindingExtensions>
        <add name="pollingDuplexBinding" 
            type="System.ServiceModel.Configuration.PollingDuplexHttpBindingCollectionElement, System.ServiceModel.PollingDuplex"/>
      </bindingExtensions>
    </extensions>
    <behaviors>
      <serviceBehaviors>
        <behavior name="DuplexCommunicationNetTcpBehavior">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <serviceThrottling maxConcurrentSessions="2147483647"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <pollingDuplexBinding>
        <binding name="DuplexNetTcpBinding" useTextEncoding="true"/>
      </pollingDuplexBinding>
      <netTcpBinding>
        <binding name="DuplexNetTcpBinding">
          <security mode="None"/>
        </binding>
      </netTcpBinding>
    </bindings>
    <services>
      <service behaviorConfiguration="DuplexCommunicationNetTcpBehavior" 
            name="DuplexCommunication.Web.StockService">
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://localhost:4502"/>
            <add baseAddress="http://localhost"/>
          </baseAddresses>
        </host>
        <endpoint address="" binding="pollingDuplexBinding" 
            bindingConfiguration="DuplexNetTcpBinding" 
            contract="DuplexCommunication.Web.IStockService"/>
        <endpoint address="" binding="netTcpBinding" 
            bindingConfiguration="DuplexNetTcpBinding" 
            contract="DuplexCommunication.Web.IStockService"/>
        <endpoint address="mex" binding="mexTcpBinding" 
            contract="IMetadataExchange"/>
      </service>
    </services>
  </system.serviceModel>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
</configuration>

Client-side code

Because we are internally using WCF, we can now have Visual Studio create a proxy for us. Add a service reference to the StockService.svc (http://localhost/StockService/StockService.svc). Apart from the proxy that is created, some code will also be generated in the ServiceReferences.ClientConfig file, as can be seen below. Note that the net.tcp endpoint is now added here; communication will take place over net.tcp on port 4502.

<configuration>
    <system.serviceModel>
        <bindings>
            <customBinding>
                <binding name="NetTcpBinding_IStockService">
                    <binaryMessageEncoding />
                    <tcpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
                </binding>
            </customBinding>
        </bindings>
        <client>
            <endpoint address="net.tcp://w500:4502/StockService/StockService.svc"
                binding="customBinding" 
                bindingConfiguration="NetTcpBinding_IStockService"
                contract="StockService.IStockService" 
                name="NetTcpBinding_IStockService" />
        </client>
    </system.serviceModel>
</configuration>

With the service reference added, we can now use the service from client code as follows. Notice that this the normal way you would access a regular WCF service from in Silverlight.

private void StartButton_Click(object sender, RoutedEventArgs e)
{
    StockService.StockServiceClient client = 
        new StockService.StockServiceClient("NetTcpBinding_IStockService");
    client.SendUpdateReceived += 
        new EventHandler<StockService.SendUpdateReceivedEventArgs>(client_SendUpdateReceived);    
    client.ConnectAsync("MSFT");
}
 
void client_SendUpdateReceived(object sender, StockService.SendUpdateReceivedEventArgs e)
{
    StockTickingTextBlock.Text = (e.request as Update).Amount.ToString();
}

Summary

The net.tcp binding offers us a great deal for creating duplex communication from within a Silverlight application: while we still have the ability to work with WCF and benefit from all its advantages like proxy generation and IntelliSense, we also have the superb performance, courtesy of TCP on which it is based. Because of the latter, it’s only usable in intranet scenarios though, because of the port restrictions.

About the author

Gill Cleeren is Microsoft Regional Director (www.theregion.com), MVP ASP.NET, INETA speaker bureau member and Silverlight Insider. He lives in Belgium where he works as .NET architect at Ordina. Passionate about .NET, he’s always playing with the newest bits. In his role as Regional Director, Gill has given many sessions, webcasts and trainings on new as well as existing technologies, such as Silverlight, ASP.NET and WPF. He also leads Visug (www.visug.be), the largest .NET user group in Belgium. He’s also the author of “Silverlight 4 Data and Services Cookbook”, published by Packt Publishing. You can find his blog at www.snowball.be.


Subscribe

Comments

  • -_-

    RE: The duplex story: looking at duplex communication in Silverlight 4 - Part 3: Using Net.Tcp


    posted by alphapapalima on Jul 30, 2010 01:37

    Great.. I got it working with the net.tcp.  Exactly what I am looking for.  I am curious though, you had mentioned in the part II, "In scenarios where the client needs to be updated because of changes in the state of the server side (for example a change in a database, a file change…), the best solution is working duplex."

    I have that scenario now where a third party application is updating our database.  When the database is updated, I would like for it to update our client (silverlight) of the changes.  Do you have an example of a database pushing changes to the silverlight client?

    Thanks.

  • -_-

    RE: The duplex story: looking at duplex communication in Silverlight 4 - Part 3: Using Net.Tcp


    posted by Gill Cleeren on Aug 02, 2010 09:49

    Interesting scenario.

    In any case, you'll still need some service sitting in between, because the database itself won't be able to push updates directly, only a service can. I'll perhaps write a sample on my blog if I find some time :)

  • -_-

    RE: The duplex story: looking at duplex communication in Silverlight 4 - Part 3: Using Net.Tcp


    posted by alphapapalima on Aug 02, 2010 18:43
    Yes, right now I do have a wcf service that is basically getting the data from sql server and pushing it to the Silverlight client using net.tcp (every 5 seconds).  I read that Query Notifications and Broker should not be used due to performance issues, so I am kind of stuck.  I would be interested (when you have time) to see what kind of solution you would come up with. 

Add Comment

Login to comment:
  *      *       

From this series