This sample uses a WCF service with the polling duplex binding to act as a chat server for a Silverlight client. The start page (Default.aspx) will launch four instances of the chat application so each of the clients can send messages to each other.
What differentiates this application from many of the other Silverlight chat samples is that the WCF service uses threads to issue callbacks to the clients. Please note that the polling duplex binding was really never meant to be used as a multicast, nor is it really scalable. This solution, however, provides a reasonable workaround to that problem.
The polling duplex binding is not ideal for multicast messages to clients because if a client is no longer connected to the service and a callback is issued to that client, then the service will hang until the timeout period expires. This example creates a thread for every client callback so that if a callback hangs, the rest of the service continues to run.
The key to this service is to use the
inactivityTimeout attribute in the bindings section. In this sample, this value is set to 10 seconds. The clients use a timer to call a function called
ImAwake based upon an
appSetting value called
ClientPingInterval, which is defaulted to 1 second. Every time
ImAwake is called, it resets the "inactivity clock" on the service for that client and starts over again.
The service is started by each client by calling the
ConnectAsynch function. This will create a
clsSession class and add it to an
ActiveSessions dictionary so the service can keep track of connected clients. When a client times out after 10 seconds due to the user shutting down the browser or some network error, the
clsSession class is automatically disposed and removed from the
ActiveSessions dictionary. In addition, each client is notified that the client has timed out so they can remove the user from the list of connected users. This example uses an observable collection and a collection view source schema to provide a sorted list of connected users in the clients.
The threaded callbacks work like the following. Each
clsSession object has a sub/function for any callback that is needed to be sent to the clients. That routine creates a new instantiation of a
ThreadedCallBack class, and then calls the appropriate function and passes in any needed parameters. The
ThreadedCallBack class will then create a new thread that runs in the background, where it then executes the client callback in a
catch statement. Since it is threaded, the service will not hang if the client is no longer connected.
Using the code
First of all, you may need to add a reference to
System.ServiceModel.PollingDuplex in the ConsoleServiceHost and SilverlightSample.Web projects. These can usually be found in the C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Libraries\Server\ directory. The next thing you want to do is decide whether you want to run the WCF service from IIS or from a console host.
If you want to run from IIS, then in the SilverlightSample.Web project, modify the web.config file and change the value for
UseConsoleService to false, and set the SilverlightSample.Web project to be the startup project. Don't forget to make sure the Default.aspx is set to be the start page.
I prefer to run my WCF services from a console host because it is a very useful way to display messages for debugging. To use the console host, set the value for
UseConsoleService to true and then right click the Solution, select the Properties page, and set "Multiple Startup Projects" to be true, and set both the ConsoleServiceHost and SilverlightSample.Web projects to run.
Please note that either way you decide to use the project, split the service model bindings into three separate files (behaviors.config, bindings.config, and services.config).
The Default.aspx startup page will launch four client browsers so you can experiment with the application. You will notice that the Default.aspx page uses some session variables which are then used in the SilverlightSampleTestPage.aspx page so it knows where to find the URL for the WCF service.
I certainly have not explained every detail about this sample, so please feel free to send me your questions and I will do the best to answer them.