Wednesday, March 16, 2011

Sending real time messages to Silverlight clients using WCF Duplex Communication

On February 23rd, Chris Whitmore from Vision Critical, Vancouver, British Columbia, gave a presentation at the Vancouver Silverlight User Group, VanSLUG, on WCF Duplex Services for Silverlight. The title of the lecture was “Using Silverlight and WCF Duplex Services to build real time collaborative applications”. An exciting topic indeed!

To introduce the audience to this technology, some of the resources that Chris used were some of Vision Critical products and an episode from Silverlight TV “Duplex Communication with WCF in Silverlight 4” by John Papa and presented by Tomasz Jamczuk from the Silverlight Web Services team.

The purpose of this article is not to discuss any of those presentations but to go a step forward in order to clarify issues which were mentioned by Tomasz and Chris but were left for the audience to explore like for example faulty connections and stale channels, how to make the client reconnect, and how to make the service deal with faulty call back channels. The code presented in this article, my homework, also pretends to provide some code sample that others can look at in order to understand better WCF Duplex.

THE SAMPLE APPLICATION
The sample application contains three projects:
  • a Silverlight application
  • a Web application running a WCF Duplex and a Web Service
  • and a Windows Phone 7 application.
The WP7 application accesses the Web Service to send a message. When the Web Service receives the message the information is added to a static data structure which the WCF has registered to for collection changed notifications. The event handler for the message collection changed publishes the message to each registered client call back channel.

The following screen-shot depicts the WP7 after sending a message using the Web Service and three different registered clients receiving the message.  Note the time intervals between messages indicating that communication channels are still active and clients have not missed a message yet.



FIRST THINGS FIRST: Registering DLLs and web.config
You need to register System.ServiceModel.PollingDuplex.dll in the web application project. You can find this DLL in:

C:\Program Files (x86)\Microsoft SDKs\Silverlight\v4.0\Libraries\Server\System.ServiceModel.PollingDuplex.dll.

Be careful and pay attention to the location because there is another System.ServiceModel.PollingDuplex.dll which can be found in the CLIENT directory. Note that you need to register the client DLL for the Silverlight application client:

C:\Program Files (x86)\Microsoft SDKs\Silverlight\v4.0\Libraries\Client\System.ServiceModel.PollingDuplex.dll.

Web.config
  












































In the case that you would like to troubleshoot your WCF Service, then un-comment the system.diagnostic element and examine the log file created in the root of the project.

THE WEB SERVICE
The Web Service class, WSMobileMessagerService, uses a worker Thread which is responsible for adding the message to the static collection of messages, , a Singleton class.

    public class WSMobileMessagerService : System.Web.Services.WebService
{
[WebMethod]
public void SendMessage(String name, String message)
{
Thread worker = new Thread(() => {
MobileMessage mobMsg = new MobileMessage()
{
Name = name,
Message = message
};
MobileMessagesCollection.MessageCollection.Add(mobMsg);
});
worker.Start();
}
}


WCF DUPLEX AND THE CALL BACK
Duplex communication occurs when a client connects to a service and provides the service with a channel on which the service can send messages back to the client.

When creating a Duplex contract we need two interfaces, the Service interface describes the operation contract that the client can call.

[ServiceContract(CallbackContract = typeof(IDuplexClient))]
public interface IDuplexMessageService
{
[OperationContract]
void Register();

[OperationContract]
void Publish(MobileMessage message);

[OperationContract]
void KeepAlive();
}


The service contract needs to specify the Call Back Contract (CallbackContract = typeof(IDuplexClient)) in the call back property. The second service contract, the call back contract, interface describes the operations that the server can invoke on the client endpoint.

    [ServiceContract]
public interface IDuplexClient
{
[OperationContract(IsOneWay = true)]
void Notify(MobileMessage message);
}

[DataContract]
public class MobileMessage
{
[DataMember]
public String Name { get; set; }

[DataMember]
public String Message { get; set; }
}

FAULTING CONNECTIONS AND CHANNELS: Stale Channels
There is no way to keep the channel open for ever and after a period of inactivity the channel goes stale and attempting to use it throws an Exception. The only way to deal with this is by getting rid of the bad channel and hope that the client registers again. The following section of code shows the implementation of the Publish() operation.

        #region Publish

public void Publish(MobileMessage message)
{
SynchronizedCollection badChannels =
new SynchronizedCollection();
foreach (IDuplexClient channel in clients)
{
try
{
channel.Notify(message);
}
catch (Exception)
{
badChannels.Add(channel);
}
}

foreach (IDuplexClient bch in badChannels)
{
clients.Remove(bch);
}
}

#endregion

FAULTING CONNECTIONS AND CHANNELS: Stale Connection on the Client side - Using KeepAlive
The implementation of the OperationContract KeepAlive in the server is is empty. This operation is invoked by a worker Thread on the client just to maintain the connection fresh otherwise the connection goes stale. In the case that connection state is Fault then the connection is created again.
private void StartDuplex()
{
client = new DuplexMessageServiceClient(
new PollingDuplexHttpBinding { DuplexMode = PollingDuplexMode.MultipleMessagesPerPoll },
new EndpointAddress("../Services/DuplexMessageService.svc"));

client.NotifyReceived += new EventHandler(client_NotifyReceived);
client.RegisterAsync();
}

private void PingServer()
{
this.pingServcie = new Thread(()=>
{
while (true)
{
if (client.State == CommunicationState.Faulted)
{
StartDuplex();
}
else
{
client.KeepAliveAsync();
Thread.Sleep(10000);
}
}
});
this.pingServcie.Start();
}

CONCLUSION
I hope that this article will serve as a supplement to those who attended the meeting. This solution addresses issues such as how to keep both endpoints alive as time passes which was accomplished by invoking the service operation KeepAlive().

DOWNLOAD HEREhttp://www.sendspace.com/file/2em3rf

Homework
Modify the application to report the location of the device and add it to a Bing Map.
  1. Modify the Web Service to take a location (Latitude and Longitude).
  2. Modify the WCF Duplex to publish the location.
  3. Add a Bing Map to your Silverlight application. You will need to research how to add the control and how to use the Bing Map service and how to add pins to the map layer.


Let me know how it goes!

References:
http://msdn.microsoft.com/en-us/library/ms731064.aspx

http://channel9.msdn.com/Shows/SilverlightTV/Duplex-Communication-with-WCF-in-Silverlight-4-Silverlight-TV-34

Friday, March 11, 2011

Consuming WCF RIA Services from a Windows Phone 7

Visual Studio 2010 has come a long way, I love the tool, but when it comes to consuming a WCF RIA Service from a WP7 the experience is a little rough, to say the least.  The process becomes frustrating when the client is required to authenticate in order to use an operation contract.  This post will describe some of the pains that I went through and the workarounds that I used.

GETTING STARTED: Download the latest Silverlight 4.0 Tooolkit  By the time of this port I used the February 2011.  You can get the latest toolkit from codeplex following this link:  silverlight.codeplex.com/releases

ADD REFERENCE TO SILVERLIGHT PROJECT:  Microsoft.ServiceModel.DomainServices.Hosting.dll C:\Program Files (x86)\Microsoft SDKs\RIA Services\v1.0\Toolkit\Libraries\Server\Microsoft.ServiceModel.DomainServices.Hosting.dll

MODIFY WEB.CONFIG
Windows Phone 7 supports a specialized version of Silvelright 3, therefore it does not support all version of WCF endpoints/bindings but it does support WS-HTTP. For this reason, for WP7 to access a WCF RIA Service the only endpoint required is the SAOP endpoint. You can copy and paste in your the following into your web.config:







ADD A SERVICE REFERENCE TO YOUR WP7 PROJECT
If I have added the my service into a directory named Services of my Silverlight application and the namespave looks like this:
namespace PatrolCenter.Web.Services
{
// using

[EnableClientAccess()]
public class RidePlanService : LinqToEntitiesDomainService
{
...

Then the URI would be like this:

< namespace_of_ria_service >-< classname_of_your_ria_service >.svc where “.” are replaced with “-“.


Save and build.  In the case that you get errors, try closing Visual Studio and starting it again.  If everything goes "OK" then click the "All Files" button in solution explorer and expand the newly added WCF RIA Service.  It should look similar to this image:

In the case that the "Reference.svcmap" is empy then this is an indication that errors need to be corrected.  This is probably the most frustrating part because no obvious errors are issued.

A1 Repo: Simple Pagination for WCF Service Operation

It is never a good idea to paginate on the client.  This post is about a simple pagination for a WCF service operation.  For this work I nee...