Wednesday, November 18, 2009

Pub/sub sample with WCF net.tcp protocol in Silverlight 4

NOTE: Many people reading this post are really looking for a publish\subscribe solution for Silverlight to implement a web chat or a stock quote application for the browser, a multiplayer online game, or some form of a web based collaboration tool, among others. If that fits your profile, you may want to check out http://laharsub.codeplex.com. Laharsub is an open source pub\sub message server for web clients, including Silverlight. It aspires to address the needs of people like you, who are interested in the subject matter of this post as well as willing to contribute your scenarios and requirements by leaving a comment. Enjoy!

Microsoft Silverlight 4 Beta unveiled at PDC 2009 adds support for WCF net.tcp protocol. The protocol enables duplex communication (sending asynchronous messages from the server to the client), and greatly improves performance compared to HTTP polling duplex protocol in Silverlight 2 and 3. This article demonstrates the use of the net.tcp protocol in the context of a pub/sub Silverlight 4 application. I am starting with the pub/sub application I used to demonstrate duplex capabilities of the HTTP polling duplex protocol before, and explaining the steps necessary to extend it to leverage the net.tcp protocol.

The full Visual Studio 10 Beta 2 solution of this Silverlight 4 sample is available for download.

Once you get the sample running, you will be able to establish asynchronous communication based on a pub/sub architecture with a single WCF service in the backend and three kinds of browser-based clients: Silverlight client using the WCF net.tcp protocol, Silverlight client using the HTTP polling duplex protocol, and AJAX client using the HTTP polling duplex protocol.

For more in-depth look at net.tcp, check out the most recent post on WCF net.tcp in Silverlight 4.

Overview

At high level, these were the most interesting steps necessary to convert the HTTP polling duplex sample I described before to support WCF net.tcp protocol added in Silverlight 4:

  1. Get the necessary tools: Visual Studio 10 Beta2 and Silverlight 4 Tools for Visual Studio 10 Beta2.
  2. Add support for net.tcp to the WCF duplex service already exposed over the HTTP polling duplex protocol.
  3. Publish the service to IIS7.
  4. Enable net.tcp activation in IIS7.
  5. Enable net.tcp protocol in IIS7.
  6. Allow Silverlight applications to communicate over TCP.
  7. Update the WCF service proxy in the Silverlight 4 application.
  8. Run and enjoy the sample.

I will describe steps 2-8 in more detail next.

Adding net.tcp support to a WCF pub/sub service

The pub/sub sample for HTTP polling duplex came with a WCF duplex service implementing the pub/sub logic. Enabling net.tcp protocol support for this service does not require any changes in the application code, and can be accomplished by adding a new endpoint in the web.config file (additions highlighted in bold):

    <system.serviceModel>
        <extensions>
        <bindings>
            <pollingDuplexBinding>
                <binding name="PubSub" useTextEncoding="true"/>
            </pollingDuplexBinding>
            <netTcpBinding>
                <binding name="PubSub">
                    <security mode="None"/>
                </binding>
             </netTcpBinding>
        </bindings>
        <services>
            <service behaviorConfiguration="Microsoft.Samples.Silverlight.PollingDuplex.Service.PubSubServiceBehavior"
                               name="Microsoft.Samples.Silverlight.PollingDuplex.Service.PubSubService">
                <endpoint address="" binding="pollingDuplexBinding" bindingConfiguration="PubSub"
                                       contract="Microsoft.Samples.Silverlight.PollingDuplex.Service.IPubSub"/>
                <endpoint address="" binding="netTcpBinding" bindingConfiguration="PubSub"
                                       contract="Microsoft.Samples.Silverlight.PollingDuplex.Service.IPubSub"/>

                <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
            </service>
        </services>
    </system.serviceModel>

This change will add a new net.tcp endpoint to the existing WCF pub\sub service. The net.tcp endpoint will exist side by side with an endpoint based on the HTTP polling duplex protocol, enabling clients to communicate with the service over either of the protocols. Metadata exchange endpoint will enable automatic generation of a client proxy for either of the protocols.

Publishing in IIS7

The development web server built into Visual Studio 10 does not support the net.tcp protocol, so you will need to deploy the web application to IIS7 to run the sample. You can use the Publish feature available for web application projects in Visual Studio to deploy the new web application to IIS7. In this article I am assuming the service will be deployed to http://localhost/pubsub.

Next, you must make sure the web application is properly configured for accepting net.tcp connections.

Enable net.tcp activation in IIS7

One important feature of IIS is the ability to activate a web application when an HTTP request targeting this application is received. Similar feature exists in IIS7 for net.tcp requests, but it may not be enabled by default depending on your system configuration. To make sure the feature is enabled or to turn it on, go to Control Panel | Programs | Turn windows features on or off and make sure WCF non-http activation is enabled:

Enable non-http activation in Windows 7

If you are running Windows 2008 server, the same feature is available through Server Manager.

To find out if net.tcp activation is enabled on your machine, go to the command line and run the following command:

sc query NetTcpActivator

The output should indicate the local service is running.

Enable net.tcp protocol in IIS7

Web applications in IIS7 can be selective about the protocols they support. When you create a new web application using the Publish feature of Visual Studio 10, it is configured to support HTTP protocol only and must be explicitly configured to enable net.tcp traffic as well. This can be done through Internet Information Services Manager. Go to the web application you have created (localhost/pubsub), choose Manage Application | Advanced Settings, and make sure net.tcp protocol is listed in Enabled protocols:

Enable net.tcp protocol for a web application

Furthermore, the web site within which the web application resides must provide net.tcp protocol binding that allows connections using desired TCP port numbers. The sample uses TCP port 4502, so the binding specification must at minimum allow this port. Go to the web site containing your web application (usually the DefaultWebSite), choose Edit Bindings, and make sure the net.tcp binding allows port 4502:

II7 binding configuration for net.tcp

To verify the WCF service is set up to accept net.tcp connections, try navigating the to the service URL in the web browser (e.g. http://localhost/pubsub/PubSubService.svc). There should be no errors and the help page for the WCF service should be displayed.

Allow Silverlight applications to communicate over TCP

For a Silverlight application to create a TCP connection to a backend server, the server must explicitly allow such a connection (this is a measure to prevent cross-domain security exploits). This is done by exposing an XML policy file over HTTP at the root of the domain where the Silverlight application is hosted, as documented at Network Security Access Restrictions in Silverlight. This is the same policy file that is also used to allow cross-domain HTTP requests from Silverlight applications, but its content is augmented to add policy for TCP connections as well.

For example, to allow all Silverlight applications to open TCP connections on ports 4502-4530 to the machine, create a clientaccesspolicy.xml file with the following content and host at the root of the document directory of your IIS server (typically c:\inetpub\wwwroot):

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="*">
        <domain uri="*" />
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true" />
        <socket-resource port="4502-4530" protocol="tcp" />
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

Open you web browser and navigate to http://localhost/clientaccesspolicy.xml to verify it will be accessible to Silverlight applications. The permit-all policy above allows unrestricted cross domain calls for both HTTP and TCP protocol over ports 4502-4530.

The section below is applicable to Silverlight 4 Beta. As of Silverlight 4 RC (and Silverlight 4 RTM), the socket policy for WCF clients using the net.tcp protocol is obtained over HTTP as opposed to TCP port 943 – please see the preceding paragraph.

For a Silverlight application to create a TCP connection to a backend server, the server must explicitly allow such a connection (this is a measure to prevent cross-domain security exploits). This is done by exposing a TCP socket policy over TCP port 943 as documented at Network Security Access Restrictions in Silverlight.

There is an online project template for Visual Studio 10 which makes this task simple by creating a windows console application serving a TCP socket policy file. The easiest way to add this project to a Visual Studio 10 solution is by searching for “silverlight tcp” in the online templates through the Add New Project dialog in Visual Studio 10:

Silverlight TCP Socket Policy online project template in Visual Studio 10

The default socket policy included in the project template allows all Silverlight applications to connect to ports 4502-4534, which is the entire range of ports available to Silverlight applications. The policy can be customized if necessary. You can also access the Silverlight TCP Socket Policy project template outside of Visual Studio

Remember to start the socket policy server application on the machine where the WCF service is hosted before running the Silverlight client!

Creating a service proxy to the WCF net.tcp pub/sub service

Creating a service proxy to a WCF net.tcp service is easy with the Add Service Reference feature of Visual Studio 10. The process is essentially the same as adding a service proxy to an HTTP based request/response or duplex service.

One feature the WCF net.tcp proxy offers beyond what HTTP polling duplex supports is integration with configuration file. During proxy generation, endpoint and binding information will be stored in the ServiceReferences.ClientConfig file, which enables the service address and other binding details to be controlled declaratively through config:

<configuration>
    <system.serviceModel>
        <bindings>
            <customBinding>
                <binding name="NetTcpBinding_IPubSub">
                    <binaryMessageEncoding />
                    <tcpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
                </binding>
            </customBinding>
        </bindings>
        <client>
            <endpoint address="net.tcp://localhost:4502/pubsub/PubSubService.svc"
                binding="customBinding" bindingConfiguration="NetTcpBinding_IPubSub"
                contract="Proxy.IPubSub" name="NetTcpBinding_IPubSub" />
        </client>
    </system.serviceModel>
</configuration>

An instance of the proxy using net.tcp protocol can be created in code by referring to the named endpoint in the configuration file:

PubSubClient client = new PubSubClient("NetTcpBinding_IPubSub");

The same proxy class can be used with HTTP polling duplex protocol, but the binding and address must be provided in code (we are working on providing configuration support for HTTP polling duplex before Silverlight 4 release):

PubSubClient client = new PubSubClient(
    new PollingDuplexHttpBinding(),
    new EndpointAddress(new Uri(App.Current.Host.Source + "/../../PubSubService.svc")));

Running the pub/sub sample

I have described key steps necessary to develop and deploy a Silverlight 4 application using the new WCF net.tcp protocol. The full Visual Studio 10 Beta 2 solution of this Silverlight 4 sample is available for download. The sample contains a pub\sub WCF server exposed over two endpoints: one using the HTTP polling duplex binding available in Silverlight 2 and 3, and the other using the WCF net.tcp protocol newly supported in Silverlight 4. There are three types of clients:

  • A pub\sub Silverlight 4 client that offers a choice of HTTP polling duplex or net.tcp protocols.
  • A pub\sub AJAX client that communicates with the server using the HTTP polling duplex protocol.
  • A publisher Silverlight 4 client that offers a choice of HTTP polling duplex or net.tcp protocols.

So what does this sample demonstrate? You can have a Silverlight 4 publisher using net.tcp protocol to publish messages to a topic managed by a WCF pub\sub service, and three pub\sub clients consuming these notifications seamlessly using net.tcp or HTTP polling duplex in Silverlight, or HTTP polling duplex in AJAX. I have added a fragment of Dante’s Divine Comedy if you think publishing stock quotes is too boring.

Publisher client using WCF net.tcp in Silberlight 4 running in Chrome Pub\sub client using WCF net.tcp protocol in Silverlight 4 running in Internet Explorer

 Pub\sub client using WCF HTTP polling duplex protocol in Silverlight 4 running in Mozilla Firefox Pub\sub client using WCF HTTP polling duplex protocol in AJAX running in Internet Explorer

You can read more about the HTTP polling duplex and AJAX aspects of the sample in several of my previous posts. For more in-depth look at net.tcp, check out the most recent post on WCF net.tcp in Silverlight 4.

38 comments:

  1. Great article.
    I have deployed your solution into II7 and I receieve following error :
    An attempt was made to access a socket in a way forbidden by its access permission.You may need contact the owner of the service to publish a cross-domain policy file.......

    I have cross-domain policy file for TCP allowing ports in range 4502-4534 to access in root.
    I have also started your SocketPolicyServer but with no success... I don't need SocketPolicyServer if I place cross-domain policy file in root of domain where service is hosted on IIS7?

    Can you help me please?

    Thanks

    ReplyDelete
  2. Any numbers on the chunked encoding in Silverlight 4?

    ReplyDelete
  3. We are working on leveraging HTTP response chunking in the polling duplex protocol in the Silverlight 4 RTM time frame (Beta does not have this feature yet). Very casual benchmarks we have conducted on the bits still in development indicate around 400% improvement over the Silverlight 3 polling duplex throughput.

    ReplyDelete
  4. Radenko, have you made sure your firewall is configured to allow incoming TCP traffic on ports 943 (the TCP policy server) and 4502 (the actual application)?

    ReplyDelete
  5. Will this work on IIS6

    ReplyDelete
  6. Fallon, IIS6 does not support net.tcp activation. This feature is only available starting in IIS7. On Windows 2003 Server your backend net.tcp service must be self-hosted in a standalone application or an NT service.

    ReplyDelete
  7. Thanks, I'll have to test this on the 2008 Server, where I have to get permission(bummer, lol).

    ReplyDelete
  8. When I publish on iis7 i have error:
    Exception: System.ServiceModel.ServiceActivationException: The service '/pubsub/PubSubService.svc' cannot be activated due to an exception during compilation. The exception message is: Configuration binding extension 'system.serviceModel/bindings/pollingDuplexBinding' could not be found

    ReplyDelete
  9. Anonymous, make sure the System.ServiceModel.PollingDuplex.dll has been deployed to the bin directory of your web application. Lack of it or an incorrect version will cause the exception message you are seeing.

    ReplyDelete
  10. We upgraded to Silverlight 4 RC and cannot connect anymore via sockets (net.tcp).
    Only OOB with sockets work.

    There is a missing piece in the security policies. But we cannot figure out what...

    It seems that MS changed the security settings regarding TCP sockets slightly...
    http://msdn.microsoft.com/en-us/library/cc645032%28VS.96%29.aspx

    Do you know what is missing? Changed?

    -------------------------------------
    Problem Details
    Could not connect to net.tcp://localhost:4502/PubSubService/PubSubService.svc. The connection attempt lasted for a time span of 00:00:00.0780078. TCP error code 10013: An attempt was made to access a socket in a way forbidden by its access permissions..
    This could be due to attempting to access a service in a cross-domain way while the service is not configured for cross-domain access. You may need to contact the owner of the service to expose a sockets cross-domain policy over HTTP and host the service in the allowed sockets port range 4502-4534.

    System.Net.Sockets.SocketException: An attempt was made to access a socket in a way forbidden by its access permissions.
    --- End of inner exception stack trace ---
    at System.ServiceModel.AsyncResult.End[TAsyncResult](IAsyncResult result)
    at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)
    at System.ServiceModel.ClientBase`1.ChannelBase`1.EndInvoke(String methodName, Object[] args, IAsyncResult result)
    at Microsoft.Samples.Silverlight.PollingDuplex.Client.Proxy.PubSubClient.PubSubClientChannel.EndSubscribe(IAsyncResult result)
    at Microsoft.Samples.Silverlight.PollingDuplex.Client.Proxy.PubSubClient.Microsoft.Samples.Silverlight.PollingDuplex.Client.Proxy.IPubSub.EndSubscribe(IAsyncResult result)
    at Microsoft.Samples.Silverlight.PollingDuplex.Client.Proxy.PubSubClient.OnEndSubscribe(IAsyncResult result)
    at System.ServiceModel.ClientBase`1.OnAsyncCallCompleted(IAsyncResult result)

    ReplyDelete
  11. Peter, the net.tcp protocol in Silverlight 4 RC expects the socket policy to be available over the HTTP protocol at the root of the domain as opposed to over TCP at port 943 as before. This means one no longer needs to host a custom TCP server to serve the socket policy file but instead can expose the policy file for TCP using the regular HTTP web server mechanisms.

    ReplyDelete
  12. Hi Tomasz
    Could you detail what we have to change in order to have the sample app working?

    ReplyDelete
  13. Hi Tomasz,

    It would be great if you update your post. Thanks in advance.

    ReplyDelete
  14. But how can I tell the WCF client proxy to use the HTTP protocol (root of the domain)?

    Per default SL4RC tries to use the socket policy server on 943

    from
    http://msdn.microsoft.com/en-us/library/system.net.sockets.socketasynceventargs.socketclientaccesspolicyprotocol%28VS.96%29.aspx

    ReplyDelete
  15. Peter, the WCF net.tcp protocol overrides the Socket's default policy protocol from TCP:943 to HTTP, so you don't have to explicitly configure this behavior. Socket's default client access policy protocol has to be TCP:943 because switching it to HTTP in Silverlight 4 would be a breaking change for Silverlight 3 applications. Given that WCF net.tcp protocol ships in Silverlight 4 for the first time, we took the freedom to pick a default which is more usable for people deploying policy files.

    ReplyDelete
  16. is there a way to test this application on the visual studio 2010 directly without using iis i tried but it's not working, i got this exception:
    Could not connect to net.tcp://localhost:4502/pubsub/PubSubService.svc. The connection attempt lasted for a time span of 00:00:02.0331163.....

    *the plolicy service is running..
    *using Silverlight 4 beta version

    Thanks

    ReplyDelete
  17. Anonymous, unfortunately one cannot host net.tcp WCF services in Cassini (the development web browser built into Visual Studio 10) - this is something that will be addressed in future releases. At the moment you should be able to host the pub\sub sample in Cassini after commenting out the net.tcp endpoint from the WCF service.

    ReplyDelete
  18. Hi Tomasz-

    Why on earth do we need a console app to host the Port 943 Silverlight policy server?

    Surely there is a way to use Tcp Activation to host the Silverlight Policy Server under IIS so that it activates automatically when a request comes in. That would be a really fantastic sample app for you to post.

    thanks,
    -Don

    That would be a great demo to post.

    ReplyDelete
  19. Anonymous,
    as of Silverlight 4 RC (and of course Silverlight 4 RTM), the socket policy for WCF clients using the net.tcp protocol is obtained over HTTP as opposed to TCP port 943 - see one of my recent comments above. Prior to Silverlight 4 RC, hosting of the socket policy over TCP port 943 required a self-hosted executable because TCP activation in IIS only works with the WCF net.tcp protocol. WCF net.tcp in turn uses .NET Framing protocol to frame discrete messages, while the protocol used to obtain socket policy over port 943 did not use any framing at all.

    ReplyDelete
  20. i tried to redo another project like your project.

    But when i want add the service web in the silverlight application, I have an error :
    contract requires Duples, but binding "WebHttpBinding" doesn't support it etc ..
    I don't understand , i put the same config in web.config.

    ReplyDelete
  21. I cannot get your code running on VS2010 RTM. I have published the PubSubService via VS2010/Publish... - after pressing F5, I can see the client application. Pressing the button "Subscribe" here runs into the following error:

    Could not connect to net.tcp://localhost:4502/pubsub/PubSubService.svc. The connection attempt lasted for a time span of 00:00:00.2850163. TCP error code 10013: Der Zugriff auf einen Socket war aufgrund der Zugriffsrechte des Sockets unzulässig.. This could be due to attempting to access a service in a cross-domain way while the service is not configured for cross-domain access. You may need to contact the owner of the service to expose a sockets cross-domain policy over HTTP and host the service in the allowed sockets port range 4502-4534.

    The German "Der Zugriff auf einen Socket war aufgrund der Zugriffsrechte des Sockets unzulässig.." means "Accessing a socket was not possible due to invalid access rights".

    It would be great, if you could update your article with instructions about how to get it up and running with the RTM release of VS2010.

    ReplyDelete
  22. Anonymous, I have updated the "Allow Silverlight applications to communicate over TCP" section of the post with information relevant to Silverlight 4 RTW. Mit freundlichen Gruessen, Tomek

    ReplyDelete
  23. The template doesn't exist anymore. The link to the template gallery doesn't work either. What's happened to the template?

    ReplyDelete
  24. Simon, the Silverlight Socket TCP Policy template has been removed from the online template gallery with the release of Silverlight 4 RTM - it is no longer necessary to connect to WCF net.tcp services. Instead, please expose socket policy over HTTP.

    ReplyDelete
  25. Hi Tomasz,

    Very good article!

    Both Clients works using net.tcp but fails if I choose HTTP polling duplex. I get "ArgumentException - The provided URI scheme 'file' is invalid; expected 'http'.
    Parameter name: via". What am I doing wrong?

    Thanks

    ReplyDelete
  26. Hi after implementing the code i get the error :
    The communication object, System.ServiceModel.Channels.ClientFramingDuplexSessionChannel, cannot be used for communication because it has been Aborted.

    if i open two different browsers and subscribe to same topic.

    ReplyDelete
  27. I wanted to thank you for this great read!! I definitely enjoying every little bit of it and I have you bookmarked to check out new stuff you post.

    ReplyDelete
  28. hello! I have been reading your blogs and they are very good. thank you for all the wonderful examples. What do I need to run this example? I have tried to run it and it gave me this error:

    Could not connect to net.tcp://localhost:4502/pubsub/PubSubService.svc

    I am trying to implement a continous service polling using Silverlight 4 with WCF and thought this example could add on to what I missing in my application. I apprecaite your help at your earliest convenience.

    ReplyDelete
    Replies
    1. You need to update your service reference to point to http://localhost/PubSubService/PubSubService.svc/mex and not
      http://localhost/pubsub/PubSubService.svc
      Additionaly
      In "Turn windows features on or off" under
      "Internet Information Services",
      "World WIde Web Services"
      "Security"
      enabled all of the options

      also under
      "Microsoft.Net Framework 3.5.1"
      enable both options for HTTP Activation.

      I have also installed local IIS7.

      It works in Development Server and IIS7 I have not tried the local express server.

      Delete
  29. Tomasz, can you look at my question regarding client.csv with net.tcp and my duplex service here http://social.msdn.microsoft.com/Forums/en-US/sharepoint2010general/thread/7d3fc412-9dc4-4881-9c11-e7020f0a4320,
    I am sure you have the answer...thanks in advance

    ReplyDelete
  30. Loads of excellent writing here. It was indeed very helpful and insightful while being straight forward and to the point. Thanks for the posting.

    ReplyDelete
  31. Very a fantastic post, i really appriciate you for this useful information its really helpful for me

    ReplyDelete
  32. I think we can see more sports updates through this website more often because the bandwith of this website is very good and easy accessable at the same time as well.

    ReplyDelete
  33. I was browsing this on google and really happy to find this blog post of yours. It solved my problem. Bookmarked the page for later reference.

    ReplyDelete
  34. Happy to see your blog as it is just what I’ve looking for and excited to read all the posts. I am looking forward to another great article from you

    ReplyDelete
  35. A normal WCF service using NET.TCP binding, a clientaccesspolicy.xml file and an exception on the server side for the required port(4502) will do the work. No need to do all the stuff mentioned above.

    For more information check:
    http://forums.silverlight.net/t/254512.aspx/1?Need+help+with+Silverlight+5+and+WCF+net+tcp+binding

    ReplyDelete
  36. I admire the valuable information in this page. I will bookmark this page and have my friends check up here often. I am quite sure they will learn lots of new stuff here than anybody else!
    Click here

    ReplyDelete

My Photo
My name is Tomasz Janczuk. I am currently working on my own venture - Mobile Chapters (http://mobilechapters.com). Formerly at Microsoft (12 years), focusing on node.js, JavaScript, Windows Azure, and .NET Framework.