Silverlight Playground
about Silverlight and other Amenities

Writing a server-less conferencing client with Silverlight 4.0 UDP Multicast

2010-01-02T22:42:07+01:00 by Andrea Boschin

When I wrote my article about , I received many questions about writing application that communicate each other with this protocol. The reason for this request is that many people believe that Silverlight being a good platform for game developers due to its great graphical features and its simplicity, so a lot of them want to implement some kind of communication for on-line collaborative games.

Local connections have not been made for this kind of usage because them are available only for communication between application instances running in the same machine and it is not possible to use them to create gaming communications.

With Silverligth 4.0 the System.Net namespace hosts a new kind of socket communications, named UDP Multicast, that seems to be a possible solution for gaming applications but also for applications requiring fast communication between multiple clients, like conferencing applications also with video streaming support.

, also know as IP Multicast, is a well-known protocol that enables the ip infrastructure to replicate messages from multiple sources to be delivered easily to an undefined number of subscribers. The protocol works using a special class of IP addresses (224.0.0.0/4 for ipV4) where each single address represent a group of clients that is communicating each other relying on the network infrastructure for the replication of the messages. This enable the creation of client applications that do not need to have a central server where clients needs to connect using the common TCP sockets.

Like the common UDP protocol, IP Multicast is a not-connected protocol that does not guarantee the arrival of the messages and the order of delivery. So if you need a realiable channel the better is to rely on TCP sockets or you need to implement some kind of consistency check.

Writing a conferencing client

The first example I wrote to test the UDP Multicast feature is a simple conferencing client that enable people to join a multicast group and then send messages to the other members of the group.  The example you can download at the end of the article is very simplified and let the user specify an username (without checking if someone else is using the same username) and join the muklticast group. Then the user can type messages and send them to all the group members.

Silverlight 4.0 has two new classes to implement a multicast client

1) UdpSingleSourceMulticastClient let work with a single well-known source that is the unique client allowed to send to the group. This is the one-to-many communication. You can imagine to write a video source with this class and multiple clients to receive packets from it.

2) UdpAnySourceMulticastClient enables all the clients both to send and receive to or from the multicast group. This let you create something similar to a conferencing application where many-to-many connection is required.

When you use a multicast client the first thing you have to do is to join the group, using the known muticast ip address (ex: 224.0.0.1) and the port (ex: 3000). When the connection have been made you can start send and/or receive from the group. Differently from the TCP sockets with UDPMulticast you do not have a restricted set of ports to use. All the ports above of 1024 are available to the plugin.

Here is a snippet from my UDPAnySourceMulticastChannel I wrote for my example:

   1: public UdpAnySourceMulticastChannel(IPAddress address, int port, int maxMessageSize)
   2: {
   3:     this.ReceiveBuffer = new byte[maxMessageSize];
   4:     this.Client = new UdpAnySourceMulticastClient(address, port);
   5: }
   6:  
   7: public void Open()
   8: {
   9:     if (!this.IsJoined)
  10:     {
  11:         this.Client.BeginJoinGroup(
  12:             result =>
  13:             {
  14:                 this.Client.EndJoinGroup(result);
  15:                 this.IsJoined = true;
  16:                 Deployment.Current.Dispatcher.BeginInvoke(
  17:                     () =>
  18:                     {
  19:                         this.OnAfterOpen();
  20:                         this.Receive();
  21:                     });
  22:             }, null);
  23:     }
  24: }

In the constructor of the class, I've created an instance of the multicast client with the required address and port, then in the Open method I've called the BeginJoinGroup method that starts an asyncronous join request to the multicast address. As always the Silverlight's communication is asyncronous so when the callback is called I need to invoke the EndJoinGroup and then marshal the thread to the user interface with using the Dispatcher.

When the group has been joined you can start receiving and sending. This two actions are simultaneous because while you are receiving messages (or you are waiting to receive) you can also send messages to the group. So you have to invoke the BeginReceiveFromGroup method that starts listening for incoming packets and calls the callback method when something has been received. While the client is waiting for something to receive you can also call the BeginSendToGroup method to send something to the group. You have to be aware that when you send a packet to the group you will also receive the packet you sent because the multicast will replicate the message to all the joined clients.

   1: private void Receive()
   2: {
   3:     if (this.IsJoined)
   4:     {
   5:         Array.Clear(this.ReceiveBuffer, 0, this.ReceiveBuffer.Length);
   6:  
   7:         this.Client.BeginReceiveFromGroup(this.ReceiveBuffer, 0, this.ReceiveBuffer.Length,
   8:             result =>
   9:             {
  10:                 if (!IsDisposed)
  11:                 {
  12:                     IPEndPoint source;
  13:                     this.Client.EndReceiveFromGroup(result, out source);
  14:                     Deployment.Current.Dispatcher.BeginInvoke(
  15:                         () =>
  16:                         {
  17:                             this.OnReceive(source, this.ReceiveBuffer);
  18:                             this.Receive();
  19:                         });
  20:                 }
  21:             }, null);
  22:     }
  23: }
  24:  
  25: public void Send(string format, params object [] args)
  26: {
  27:     if (this.IsJoined)
  28:     {
  29:         byte[] data = Encoding.UTF8.GetBytes(string.Format(format,args));
  30:  
  31:         this.Client.BeginSendToGroup(data, 0, data.Length,
  32:             result =>
  33:             {
  34:                 this.Client.EndSendToGroup(result);
  35:             }, null);
  36:     }
  37: }

The UDPAnySourceMulticastClient class has some other interesting methods. You can send messages to the group specifing the destination so the network infrastructure will route the message to a single target. You can also block and unblock an IPAddress to prevent messages incoming from it to be received.

There is not a "Disconnect" or "Close" method but when you need to end the communication you can call the Dispose method of the client class. This will cause the pending receive to be dropped. It is important to have a flag set when the class is disposing because when the pending receive is dropped your callback is notified and you have to be aware that the client instance is not valid anymore and avoid to call the EndReceiveFromGroup method alse you will get an exception.

   1: /// <summary>
   2: /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
   3: /// </summary>
   4: public void Dispose()
   5: {
   6:     if (!IsDisposed)
   7:     {
   8:         this.IsDisposed = true;
   9:  
  10:         if (this.Client != null)
  11:             this.Client.Dispose();
  12:     }
  13: }

The client needs only to create an instance of the class an then call the Open method to join the multicast group. The channel then automatically starts listening from incoming packets and raise an event every time it detect something. So when the user hit the send button it I can call the Send() method to send a new packet and when the channel notify me about the arrival of a packet I add it to the logging listbox. I've added an AfterOpened and BeforeClose events to allow the client to send a message just after joining the group and before leaving it.

PolicyServer

Like other networking tools in Silverlight, the ip multicast requires something issuing a policy file. This is the sole server-side requirement for this protocol working fine. The policy server has to implement a two UDP messages system. The first message, sent by the client, is a datagram called "announcement" that asks the server to issue a policy file. When the server receive this message have to send an xml file that authorize to the client to communicate with a particular ip address and port. The mechanism is very similar to the TCP socket policy server but use an UDP messagging system.

To implement this server the best is downloading this project from MSDN code gallery. The project contains a working policy server that you can simply start from a console application or from a win32 service.

The drawbacks

The application I have included at the end of the article is very simple and demostrate the power of this messaging system, that was initially designed for effective video streaming. Unfortunately there is some drawbacks. First of all, also if I've entitled this example "server-less" this is true for the 99%. You need a policy issuer that is a little server, but it is not crucial for performance concerns. The system is really simpler than an always-connected TCP implementation and due to the nature of the UDP protocol really require less resources.

Another concern is about the security and realiability. The UDP protocol does not implements some infrastructure to avoid the ip spoofing and does not guarantee the packet delivery and the arrival order. In a real world solution you have to be aware of these limitation and take care of them. You have to write code to sign packets to know from whom they are issued and to handle packet loss and unordered delivery. This may be someway complex, but is a little price to pay for the effectiveness of this protocol.

Finally, the major drawback is that the most common firewalls manage to block this kind of traffic. If using a TCP socket server on a well known port is someway difficult due to the need of having firewall configurations, implementing a multicast is probably more complex specifically if you need to send the packets through the Internet. So in my opinion the most common scenario for this protocol to work is a local area network where you can manage to have firewalls and network infrastructure comply with it.

Download: SilverlightPlayground.UDPMulticast.zip (181 KB)

Categories:   Networking
Actions:   E-mail | del.icio.us | Permalink | Comments (0) | Comment RSSRSS comment feed

How to configure an AuthenticationDomainService using Ria Services Class Library

2009-11-06T11:36:01+01:00 by Andrea Boschin

Using a Ria Services Class library to collect DomainServices and DomainContexts in a solution is a good practice because everyone know the value of having classes separated in projects instead of having them in the web project.

If you try to create this kind of project and then you add an Authentication Domain Service with the July 2009 CTP of Ria Services you will find two major drawbacks. First of all you will notice the generated code does not contains a RiaContext class. RiaContext is the class responsible to handle the User and roles and configure the type of Authentication to use in the application.

To workaround to this problem you may simply write by hand this class and put it in the client side part of the Ria Services library project. The code can be copied by an AuthenticationDomainContext generated in the web project but it is very simple and I show you the code here:

   1: public sealed partial class RiaContext : System.Windows.Ria.RiaContextBase
   2: {
   3:     #region Extensibility Method Definitions
   4:  
   5:     partial void OnCreated();
   6:  
   7:     #endregion
   8:  
   9:     public RiaContext()
  10:     {
  11:         this.OnCreated();
  12:     }
  13:  
  14:     public new static RiaContext Current
  15:     {
  16:         get
  17:         {
  18:             return ((RiaContext)(System.Windows.Ria.RiaContextBase.Current));
  19:         }
  20:     }
  21:  
  22:     public new User User
  23:     {
  24:         get
  25:         {
  26:             return ((User)(base.User));
  27:         }
  28:     }
  29: }

With this class you can configure the Authentication Domain Context as you did with the generated class. So you have to add it to the App.config, in the ApplicationLifetimeObjects tag and then add a kind of authentication like the WindowsAuthentication and FormsAuthentication.

The second drawback is that if you run the project this way and then you call the Login() method (or any other method) of the RiaContext you will get an error:

The DomainContextType is null or invalid and there are no contexts generated from AuthenticationBase<T>

This probably come from the fact that the RiaContext is not correctly initializated so when the class search for a valid domaincontext to handle the Login call it fails because it does not find it. The tip to correct this behavior is to specify the DomainContext property in the Authentication you have choosed. Here is how to change the App.xaml file:

   1: <Application.ApplicationLifetimeObjects>
   2:     <slpgria:RiaContext>
   3:         <slpgria:RiaContext.Authentication>
   4:             <appsvc:FormsAuthentication>
   5:                 <appsvc:FormsAuthentication.DomainContext>
   6:                     <slpgdc:MyAuthenticationDomainContext />
   7:                 </appsvc:FormsAuthentication.DomainContext>
   8:             </appsvc:FormsAuthentication>
   9:         </slpgria:RiaContext.Authentication>
  10:     </slpgria:RiaContext>
  11: </Application.ApplicationLifetimeObjects>

As you can see you have simply to give an instance of the generated Authentication Domain context class to the FormsAuthentication (or Windows Authentication as well). The RiaContext need to have this instance to make the calls to the BL methods in the Domain Service.

I really do not know if this behavior will be corrected in the next releases of RiaServices. The solution is pretty simple but take me some hours to understand what are going wrong. So I hope this may help you to spare some time making your experiments with the current release.

Categories:   TIPS | Networking
Actions:   E-mail | del.icio.us | Permalink | Comments (7) | Comment RSSRSS comment feed

Handling duplicated connections on Polling Duplex

2009-10-23T00:46:00+01:00 by Andrea Boschin

The last tip I would like to propose is a tecnique to avoid a single client machine connect multiple times to the same polling server. This may be the case when the user starts two or more instances of the browser or open the same page in multiple tabs. In this scenario may be unuseful to have every page connected to the server.

In Silverlight 3.0 there is a way to check when a plugin has been loaded many times. When you try to create a LocalReceiver with the same name from two instances you get an exception because they cannot share the same name. So using a LocalReceiver you can check if another browser is open.

   1: public override void Start()
   2: {
   3:     LocalMessageReceiver receiver = this.CreateReceiver();
   4:  
   5:     if (receiver != null)
   6:     {}  // receiver created: I'm the master...
   7:     else
   8:     {}  // cannot create receiver: I'm a slave...
   9: }
  10:  
  11: private LocalMessageReceiver CreateReceiver()
  12: {
  13:     try
  14:     {
  15:         LocalMessageReceiver receiver = new LocalMessageReceiver("PollingReceiver");
  16:         receiver.Listen();
  17:         return receiver;
  18:     }
  19:     catch(ListenFailedException)
  20:     {
  21:         return null;
  22:     }
  23: }

 

Checking the presence of another instance is only half of the work to do. When you detect you are a slave in the machine you need to avoid connecting - slave does nothing because a master already exists - and probably you have to change the user interface to let the user know that there is another instance running.

In my application I need to check the presence of the master every few seconds to let a slave becoming a master. To do this I've created two classes MasterPollingClientCode  SlavePollingClientCore implementing the same interface IPollingClientCore. The first class connect to the server and the other class simply does nothing.

   1: public override void Start()
   2: {
   3:     LocalMessageReceiver receiver = this.CreateReceiver();
   4:  
   5:     if (receiver != null)
   6:         this.Core = new MasterPollingClientCore(this.SessionId, this.EndPoint, receiver);
   7:     else
   8:         this.Core = new SlavePollingClientCore(this.LocalId, 
                          new LocalMessageSender("PollingSender" + this.LocalId.ToString()));
   9:  
  10:     this.Core.AlarmReceived += new EventHandler<NotifyAlarmReceivedEventArgs>(Core_AlarmReceived);
  11:     this.Core.Connected += new EventHandler(Core_Connected);
  12:     this.Core.Disconnected += new EventHandler(Core_Disconnected);
  13:     this.Core.Fault += new EventHandler<PollingFaultEventArgs>(Core_Fault);
  14:     this.Core.Start();
  15:     base.Start();
  16: }
 

The container class, then starts a thread. This thread try to create a new LocalReceiver and when it is able to get an instance it change the core class from slave to master and connect to the server. This way the client is always connected to the server with alwasy one simple connection:

   1: protected override void ThreadProc()
   2:     {
   3:         Debug.WriteLine("ThreadProc");
   4:  
   5:         while(WaitHandle.WaitTimeout == WaitHandle.WaitAny(this.ExitHandles, 5000))
   6:         {
   7:             if (this.Mode != PollingClientMode.Master)
   8:             {
   9:                 Deployment.Current.Dispatcher.BeginInvoke(
  10:                     ()=> this.TryConvertToMaster());
  11:             }
  12:         }
  13:     }
  14:  
  15:     /// <summary>
  16:     /// Tries the convert to master.
  17:     /// </summary>
  18:     private void TryConvertToMaster()
  19:     {
  20:         Debug.WriteLine("TryConvertToMaster");
  21:  
  22:         LocalMessageReceiver receiver = this.CreateReceiver();
  23:  
  24:         if (receiver != null)
  25:         {
  26:             Debug.WriteLine("created");
  27:  
  28:             // detach all
  29:             this.Core.Stop();
  30:             this.Core.AlarmReceived -= new EventHandler<NotifyAlarmReceivedEventArgs>(Core_AlarmReceived);
  31:             this.Core.Connected -= new EventHandler(Core_Connected);
  32:             this.Core.Disconnected -= new EventHandler(Core_Disconnected);
  33:             this.Core.Fault -= new EventHandler<PollingFaultEventArgs>(Core_Fault);
  34:             // create new core
  35:             this.Core = new MasterPollingClientCore(this.SessionId, this.EndPoint, receiver);
  36:             // attach all
  37:             this.Core.AlarmReceived += new EventHandler<NotifyAlarmReceivedEventArgs>(Core_AlarmReceived);
  38:             this.Core.Connected += new EventHandler(Core_Connected);
  39:             this.Core.Disconnected += new EventHandler(Core_Disconnected);
  40:             this.Core.Fault += new EventHandler<PollingFaultEventArgs>(Core_Fault);
  41:             this.Core.Start();
  42:         }
  43:     }
 
 

If you are brave you can try to implement a communication between Slave and Master using a LocalSender. Using the code I provider this task cannot be too hard.

Good Work

Categories:   Networking
Actions:   E-mail | del.icio.us | Permalink | Comments (1) | Comment RSSRSS comment feed

How to avoid flooding a PollingDuplex server

2009-10-06T14:37:39+01:00 by Andrea Boschin

Returning on the PollingDuplex argument, today I would like to illustrate a tecnique I used to avoid the flooding in my Polling Duplex service. The problem come from the fact that my server retain a list of connected clients and is unable to detect the disconnection in a short time. After a while the notification from the server to the disconnected client will timeout so the server handle the timeout and remove the client from its list. But if for some reason a client Register itself multiple times the server notification list will grow and this may become a problem causing the service to slow down its response time.

In a recent project I have to address this issue because of the way the polling client works. Imagine having a instant messaging client using PollingDuplex in all the pages of a portal. When the user navigate in the website the polling client will repeatly connect and disconnect from the polling server because the user may change page after short time.

How to generate a persistent ClientID

To handle this problem I need to have a globally unique id identifing the connecting client. If the ID is unique across different connected clients the server can use this ID to search previuos instances of the client in his notification list and if found it discart the old client and replace it with the new one. The solution is pretty simple but it require the ability to generate a very unique id (obviously a Guid) and then persist it across different browser session.

The trick is to use the Isolated Storage. The first time I start the client it generate the Guid and save it in the IsolatedStorageSettings collection. Then it use the guid to connect and register to the polling server.

All the other times the client find the Guid in the IsolatedStorageSettings and avoid to generate another Guid but use the old identifier. Here is the code to generate the guid or take id from the storage:

   1: private void Application_Startup(object sender, StartupEventArgs e)
   2: {
   3:     Guid key;
   4:  
   5:     if (!IsolatedStorageSettings.ApplicationSettings.Contains("InstanceKey"))
   6:     {
   7:         key = Guid.NewGuid();
   8:         IsolatedStorageSettings.ApplicationSettings["InstanceKey"] = key;
   9:         IsolatedStorageSettings.ApplicationSettings.Save();
  10:     }
  11:     else
  12:         key = (Guid)IsolatedStorageSettings.ApplicationSettings["InstanceKey"];
  13:  
  14:     this.RootVisual = new MainPage(key.ToString());
  15: }

I put the code in the Application_Startup method then I pass the key to the MainPage constructor because it must use the guid to connect to the server.

On the server side I've slightly changed the Register method and the Polling thread to handle the new guid. First of all I request the id in the Register method:

   1: public void Register(string sessionId)
   2: {
   3:     IPollingServiceClient client =
   4:         OperationContext.Current.GetCallbackChannel<IPollingServiceClient>();
   5:  
   6:     PollingMonitor.Current.Register(client, sessionId);
   7: }

Then the server checks his notification list to add or change the callback client:

   1: /// <summary>
   2: /// Adds the specified item.
   3: /// </summary>
   4: /// <param name="item">The item.</param>
   5: public void Add(IPollingServiceClient client, string sessionId)
   6: {
   7:     var found = (from c in this
   8:                  where c.SessionId == sessionId
   9:                  select c).SingleOrDefault();
  10:  
  11:     if (found != null)
  12:         found.ChangeClient(client);
  13:     else
  14:         this.Add(new PollingClient(client, sessionId));
  15: }

The ChangeClient() method simply put the new callback client in the object instance representing the client in the list.

There are only two drawbacks in this tecnique. The first is that the user can clear his IsolatedStorage using the Silverlight context menu. This deletes the saved Guid so the next time the client connect to the server it generate another Guid. On the other side someone may discover some privacy concerns on having an id globally identifying the client because this may become a way to track the user activities. You have to be aware of this problem and eventually you can mitigate the problem using a TTL to invalidate the Guid after some hours or days so the client will change the Guid and the tracking become hardest.

Categories:   TIPS | Networking
Actions:   E-mail | del.icio.us | Permalink | Comments (0) | Comment RSSRSS comment feed

Handling faults on PollingDuplex while server is not available

2009-09-25T15:57:34+01:00 by Andrea Boschin

During the development of the project I'm currently working I've implemented a polling duplex client and I found some improvements to the code I've published some weeks ago in this post.

The problem I would like to answer here is caused by server unavailability that may origin in many causes. In my scenario I'm using a WCF service hosted by Internet Information Server. While I'm using a server-side thread running in the context of the Application Pool there may be some conditions where Application Pool is recycled so the server thread is aborted and the PollingDuplex communication stops.

There is many reasons why we have to avoid this condition. In my case it is important that the client continue receive updates from the polling server without it require a page refresh from the user. So I've implemented a fault handling procedure that let my client detect when the server become unavailable and then it retry connecting and restart server side thread.

First of all we have to write a registration procedure. My duplex channel work using a Register() ServiceOperation called by the client that subscribe the client in the server thread for updates notification. The client callback contract has a single NotifyAlarm() method used by the server to notify messages to client. Here is the client-side code I use to start the polling:

   1: /// <summary>
   2: /// Registers this instance.
   3: /// </summary>
   4: private void Register()
   5: {
   6:     this.Client = new PollingServiceClient(
   7:         new CustomBinding(
   8:             new PollingDuplexBindingElement
   9:                 {
  10:                     InactivityTimeout = new TimeSpan(1, 0, 0),
  11:                     ClientPollTimeout = new TimeSpan(0, 1, 0)
  12:                 },
  13:             new BinaryMessageEncodingBindingElement(),
  14:             new HttpTransportBindingElement()),
  15:         this.EndPoint);
  16:  
  17:     this.Client.NotifyAlarmReceived += 
  18:         new EventHandler<NotifyAlarmReceivedEventArgs>(Client_NotifyAlarmReceived);
  19:     this.Client.InnerChannel.Faulted += 
  20:         new EventHandler(Client_Faulted);
  21:     this.Client.RegisterCompleted += 
  22:         new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(Client_RegisterCompleted);
  23:     this.Client.RegisterAsync(this.SessionId);
  24: }

To handle channel fault I subscribe the Faulted event in the InnerChannel. I cannot find any other way to detect when the polling fail due to server unavailability. If you trace the polling of the client and then simulate the server unavailability, recycling the application pool you will see a 404 error (if you use ClientHttpStack the error will be more specific).

Untitled

When this error occur the InnerChannel.Faulted event is raised so you can restart the polling calling the Register() method again. In the Faulted event handler I simply call the Register method again. 

   1: /// <summary>
   2: /// Handles the Faulted event of the Client control.
   3: /// </summary>
   4: /// <param name="sender">The source of the event.</param>
   5: /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
   6: void Client_Faulted(object sender, EventArgs e)
   7: {
   8:     Deployment.Current.Dispatcher.BeginInvoke(
   9:         () =>
  10:         {
  11:             this.OnDisconnected();
  12:             this.Register();
  13:         });
  14: }

The better will be starting a Timer to retry connection on a regular timeout to let the client returning online after longer server unavailability. This may be useful also when we start the polling because we can dowload the Silverlight application from a server but then it starts the polling to another server. So I've added some code in the RegisterCompleted event handler and when I get an exception from the Register() method I start a separate thread. It waits for 60 seconds then recall the Register() method again.

   1: void Client_RegisterCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
   2: {
   3:     if (e.Error == null)
   4:         this.OnConnected();
   5:     else
   6:     {
   7:         this.OnFault(e.Error);
   8:  
   9:         ThreadPool.QueueUserWorkItem(
  10:             (o) =>
  11:             {
  12:                 Thread.Sleep(60000);
  13:  
  14:                 Deployment.Current.Dispatcher.BeginInvoke(
  15:                     () => this.Register());
  16:             });
  17:     }
  18: }

You have to be aware that the Faulted event require you to marshal the context of the thread before updating any UI element. In my code I raise an event of a wrapper object to let UI reflect the temporary disconnection. So I have to use the Dispatcher to marshal the Thread to the UI.

This is all for now. I will write more on this argumet on the next days to handle a different condition.

Categories:   Networking
Actions:   E-mail | del.icio.us | Permalink | Comments (0) | Comment RSSRSS comment feed

Silverlight 3.0 RTW: A new HTTP stack ready for REST

2009-07-10T17:45:00+01:00 by Andrea Boschin

The paradigm behind REST services is very fascinating while it allow to manipulate resources over the network relying to Uri and Http Methods. For a few of you that are not aware of what REST means I suggest to think at the web because it is the more REST thing you know. When you are pointing your browser to a "resource" on the Internet, for example a product in a ecommerce website, you will write an Url in the browser that univocally identify the product. You now can imagine to use Http Methods to operate on this resource: the GET verb will retrieve information about it, the PUT updates the resource, the POST creates it and finally the DELETE remove the resource from the web. In a few words these are REST operations and is very cool to be able to use this paradigm to access resources from a Database. ADO.NET Data Services is born to implement this paradigm into the .NET Framework 3.5 SP1, and many libraries has been build to support different technologies, Windows Forms, WPF, ASP.NET. And obviously Silverlight 2.0 come with an implementation of a Data Service client to operate with REST resources but it is not really RESTful as you may believe the first time you use it.

The problem with Silverlight 2.0, due to limitations to the http stack coming from the use of the Browser API, is that it cannot handle all the required http methods but only the GET and POST verbs. So to workaround this limitation the Data Service library simply use POST to send PUT and DELETE operations. This workaround violate the REST paradigm and it imply you are not able to use 3rd party REST resources.

What I've briefly explained in the previous paragraphs is the main reason we really need a new http stack to overcome this limitations and to be able to implement a full REST interface. This is not the only benefit we can give for the addition of new verbs: let think for example to a new way to upload files to the server, using the PUT method.

The latest release of Silverlight 3.0 got new features going in the direction I've just explained. In the next paragraphs I will explain how to use them by exploring the pretty new http Stack, called ClientHttp.

BrowserHttpStack vs ClientHttpStack

First of all we need to know that the new http stack is completely separated from the old stack. This is an important note while we are sure the old stack remain unaltered and our applications relaying on it continue to work without any change. All the working things we already know continue to work over this stack and does not use the new one.

The ClientHttpStack in opposite to the BrowserHttpStack (these are the official names of the two actors) can be created using a static class called WebRequestCreator. This class can create instances of HttpWebRequest for both the browser and the client stack. Here is a sample showing the usage of the class.

   1: // create an instance of the Client stack
   2: HttpWebRequest rq = (HttpWebRequest)WebRequestCreator.ClientHttp.Create(uri);
   3:  
   4: ...or...
   5:  
   6: // create an instance of the Browser stack
   7: HttpWebRequest rq = (HttpWebRequest)WebRequestCreator.BrowserHttp.Create(uri);

The HttpWebRequest created by this call is exactly the same we have used since Silverlight 2.0 so it can easily replace the browser stack in every existing application with a few line of code. We can immediately test the new stack assigning the Method property with the "PUT" value:

rq.Method = "PUT";

As we expect while the old stack thrown a "method not supported" exception, the new stack accept this assignment. Not all the http methods are allowed. Using TRACE, TRACK or CONNECT raise an error probably for security reasons. We will go deep inside some of the available methods in the next paragraph.

But this is only the most evident difference. Watching for the properties of the HttpWebRequest we will find a CookieContainer. It let us manage the cookies of the request. The old stack rely on cookies issued by the browser and it shares them with the browser itself. In the new stack we have full control of issued cookies; we can access cookies sent by the server or create our own cookies and send them. The drawback is that we cannot share cookies between client stack and browser stack but only rely on automatic management of server cookies from the client stack to allow forms authentication scenarios.

The next sample show how to use the CookieContainer to send our cookies:

   1: HttpWebRequest rq = (HttpWebRequest)WebRequestCreator.ClientHttp.Create(uri);
   2: rq.Method = "GET";
   3: rq.CookieContainer = new CookieContainer();
   4: rq.CookieContainer.Add(
   5:     uri, new Cookie("Author", "Andrea Boschin"));

Another great news, many people will really appreciate, is that the new stack is capable of retrieving status codes from the http response. One of the most common problems with Silverlight 2.0, especially the first time someone try to use the HttpWebRequest is the unability to get errors from the server. This is because the browser do not send all status codes to the plugins but only 404 (Not Found) and 200 (OK). The forum is filled of disoriented people not understanding why they get a 404 from the server while they are calling an existing uri and the most common suggestion is to use fiddler to search the error in the traced call.

To read status codes from the response we have to catch the WebException and then get the HttpWebResponse from the exception. This may seems a bit strange but is really simple. Here is the code:

   1: rq.BeginGetResponse(
   2:     r =>
   3:     {
   4:         try
   5:         {
   6:             WebResponse rs = rq.EndGetResponse(r);
   7:             // do something with response...
   8:         }
   9:         catch (WebException ex)
  10:         {
  11:             HttpWebResponse rs = (HttpWebResponse)ex.Response;
  12:  
  13:             MessageBox.Show(
  14:                 string.Format("Webserver returned status code {0}: '{1}'", 
  15:                     (int)rs.StatusCode, 
  16:                     rs.StatusDescription));
  17:         }
  18:     }, rq);

These features is really useful but they are not used from existing classes. WCF and WebClient can only use the classic http stack. To have access to the ClientHttpStack we have to use the HttpWebRequest and dealing with problems like thread syncronization that are solved by the WebClient. But the new stack is very important and now it is time to have some samples about usage of the http methods.

GET, POST, PUT & DELETE

In the sample solution attached at the end of this article I've enclosed a sort of file system browser application. It use the new http stack to make calls to the server and retrieve xml containing the response. This kind of application was possible also with Silverlight 2.0 but to explaing usage of http methods I've used them to mimic some filesystem operations. GET will list the content of a folder, PUT upload a file or create a directory, POST is used to send credentials and finally DELETE remove files and directories.

Doing an http call is very similar to using the previous stack. We need to create an instance of the stack, set the method we want to use and then create a request as the server will expect it. The following sample make a call to get the directory content. I've splitted the operations in two methods, one doing the raw http call and the other using this low-level method create the request and parse the result. This is the low-level DoGet() method:

   1: private static void DoGet(Uri uri, Action<Stream> success, Action<Exception> fail)
   2: {
   3:     try
   4:     {
   5:         HttpWebRequest rq = (HttpWebRequest)WebRequestCreator.ClientHttp.Create(uri);
   6:         rq.Method = "GET";
   7:         rq.CookieContainer = new CookieContainer();
   8:         rq.BeginGetResponse(
   9:             new AsyncCallback(
  10:                 r =>
  11:                 {
  12:                     try
  13:                     {
  14:                         WebResponse rs = rq.EndGetResponse(r);
  15:                         success(rs.GetResponseStream());
  16:                     }
  17:                     catch (WebException ex)
  18:                     {
  19:                         fail(CreateFailFromWebException(ex));
  20:                     }
  21:                 }), null);
  22:     }
  23:     catch (Exception ex)
  24:     {
  25:         fail(ex);
  26:     }
  27: }

The code in this listing shows the usual way to place an http call. First of all the DoGet method require I specify two callback methods to be called when the request will succeed or fail. This pattern helps to simplify the code to write avoiding handling multiple event handler. Using lambda expressions the code become very compact.

After the creation of the client stack I initialize the "Method" property with the GET verb, then I create an instance of a CookieContainer to allow the request to handle cookies. Finally calling BeginGetResponse place the call to the specified uri. When this method is called a new thread is created; In my case the body of the inner lambda expression contains the code executed in the thread. It call the EndGetResponse method (this trigger the call to the webserver) and finally ask for the Stream containing the body of the response.

As I explain in the previous paragraph I have to catch the WebException to read http status codes and translate it to an call to the fail() callback. You have to be aware that the two try-catch blocks are executed in different threads so the external block is unable to catch exception coming from the body of the lambda expression. This is the reason for having two separated blocks calling the fail method. Now watch to the following code:

   1: public static void GetDirectory(string path, Action<FileSystemItem[]> success, Action<Exception> fail)
   2: {
   3:    Uri uri = new Uri(
   4:        DataSource.ServiceUri +
   5:        "?action=directory" +
   6:        "&path=" + HttpUtility.UrlEncode(path));
   7:  
   8:    DataSource.DoGet(uri,
   9:        r =>
  10:        {
  11:            try
  12:            {
  13:                XDocument document = XDocument.Load(r);
  14:                IEnumerable<FileSystemItem> directories = DataSource.DeserializeItems(document);
  15:                Deployment.Current.Dispatcher.BeginInvoke(() => success(directories.ToArray()));
  16:            }
  17:            catch (Exception ex)
  18:            {
  19:                Deployment.Current.Dispatcher.BeginInvoke(() => fail(ex));
  20:            }
  21:        },
  22:        e => Deployment.Current.Dispatcher.BeginInvoke(() => fail(e)));
  23: }

This is the high-level method to get the directory content.  It use the same asyncronous pattern but maps the calls to the callback methods to the UI thread using an instance of the Dispatcher. While the HttpWebRequest make the calls in a different thread we need to marshal the context of the call to avoid cross-thread exception when we try to reach some UI components.

Using PUT to upload a file

Showing all the methods one-by-one is too much long. But there are another (last)  method I want to show. It is the PUT method we can use to upload files to a webserver in an alternate (and most simple) way to the use of the POST method. While the POST method require encoding the resource to base64 and forge a complex request, the PUT method simply ask to enqueue the full binary content. Here is the client code:

   1: private static void DoPut(Uri uri, FileStream file, Action<Stream> success, Action<Exception> fail)
   2: {
   3:     try
   4:     {
   5:         HttpWebRequest rq = (HttpWebRequest)WebRequestCreator.ClientHttp.Create(uri);
   6:         rq.Method = "PUT";
   7:         rq.CookieContainer = DataSource.Cookies;
   8:         rq.BeginGetRequestStream(
   9:             new AsyncCallback(
  10:                 result => DataSource.DoPutUpload(result, file, success, fail)), rq);
  11:     }
  12:     catch (Exception ex)
  13:     {
  14:         fail(ex);
  15:     }
  16: }
  17:  
  18: private static void DoPutUpload(IAsyncResult result, FileStream file, Action<Stream> success, Action<Exception> fail)
  19: {
  20:     HttpWebRequest rq = (HttpWebRequest)result.AsyncState;
  21:  
  22:     using (Stream stream = rq.EndGetRequestStream(result))
  23:     {
  24:         int read = 0;
  25:         byte[] buffer = new byte[1024];
  26:  
  27:         while ((read = file.Read(buffer, 0, buffer.Length)) > 0)
  28:             stream.Write(buffer, 0, read);
  29:     }
  30:  
  31:     rq.BeginGetResponse(
  32:         r =>
  33:         {
  34:             try
  35:             {
  36:                 WebResponse rs = rq.EndGetResponse(r);
  37:                 success(rs.GetResponseStream());
  38:             }
  39:             catch (WebException ex)
  40:             {
  41:                 fail(CreateFailFromWebException(ex));
  42:             }
  43:         }, rq);
  44: }

The first method (DoPut) is very close to the previous method I described. The core of the upload is the DoPutUpload. It open a stream in the HttpWebRequest and write the entire content of the file to upload just before calling the EndGetRequest. When this call is made the file is send on the network to the webserver. I use an httphandler and when the PUT is receives read from the InputStream the file I write to the filesystem.

   1: private void ProcessFileRequest(string path)
   2: {
   3:     this.EvaluateIsValidUser();
   4:  
   5:     if (File.Exists(path))
   6:         throw new Exception("File already exists");
   7:  
   8:     using (FileStream stream = File.OpenWrite(path))
   9:     {
  10:         byte[] data = new byte[1024];
  11:         int read = 0;
  12:  
  13:         while ((read = this.Context.Request.InputStream.Read(data, 0, 1024)) > 0)
  14:             stream.Write(data, 0, read);
  15:     }
  16:  
  17:     this.WriteOk();
  18: }

The last code runs on the server. It receive the path of the file to write and create it in the file system. The final WriteOk() method show I can write something on the response to notify the client it have successful uploaded the file.

Some final words

The main benefit coming with the introduction of the new stack is the opportunity to be able to get access to rest resources on the internet. This is the reason for the creation of this stack someone can consider a duplication on something already exists. But the presence of new methods, the cabapility to better handle server status codes and cookies give to Silverlight 3.0 a new resource to implement great applications.

The code I attached to this article show a full implementation of all the http methods I've talk about. You have only to change the server path where the filesystem has to be explored. You can achive this by changing the BaseFolder property in the HttpRequestManager class.

Download: Elite.Silverlight3.ClientHttpStack.zip (2,1 MB)

Video: ClientHTTPStack.wmv (10,1 MB)

Categories:   Networking | News
Actions:   E-mail | del.icio.us | Permalink | Comments (8) | Comment RSSRSS comment feed

Improve PollingDuplex reliability with Silverlight 3.0

2009-04-07T23:43:23+01:00 by Andrea Boschin

The need to consume a continuous flow of data from a RIA application has two tipical solution. The first one involve the use of a Socket channel and probably is the most realiable when there is full acces to the ports  exposed by a server to the network. But this is rarely an available solution. Firewall, proxies and other kind of network apparates often restrict the access to a very tiny set of ports, possibly only to the http port 80. In this case the last solution available is to continuous poll the server and pulling data at every timeout.

timetableThis tecnique is slightly inefficient and prone to overload the server. If the need is to have very fast updates you have to rely on very short timeout but this may cause the server to fail under a great number of clients. On the other side having a long timeout may lost precision on the updates and give bad informations to users.

Silverlight 2.0 introduced a new mode to consume WCF services that allow to have the better of the server polling, using the only available http port, without short timeouts. With long timeouts we may also have updates very quickly thanks to a smart polling tecnique. Polling a server usually cause the client to be connected to the server only for few milliseconds and between connections there is a long disconnected period (the timeout). With Silverlight 2.0 PollingDuplex, channels can be connected during the whole timeout period and disconnect only for the short time needed to refresh the connection or notify the client of available updates. To do this "magic" the PollingDuplex simply open a connection to the server and wait for this connection to expire for a given period of time. If something happen on the server during this waiting the connection will be closed by the server itself and the client receive the notification with the related data.

Since its implementation many months ago this tecnique has been covered by many articles on the Internet so we do not need to add some other words to them. Here we need instead to analyze the changes that Silverlight 3.0 have introduced in this implementation that grant the developer a more reliable and simple usage of the PollingDuplex channels. To explore this new model I introduce a simple but effective application that monitors bus traffic.

Setup PollingDuplexHttpBinding

With Silverlight 2.0 setting up a duplex channel was a task hard and prone to errors. Due to the missing of an auto generated proxy the creation of a duplex connection and the control of its lifetime involve the direct usage of WCF channels and the management of at least a thread to monitor the polling channel. A detailed article explaining this tecnique may be found .

The main activity for the Silverlight team on this feature was to simplify the task of establishing the connection. With Silverlight 3.0 Visual Studio now support the generation of proxy class directly from the IDE in a similar way what we do with normal WCF services.

After the creation of the proxy - where it is possible to set properties like the type to be used for collections and dictionaries - the IDE generates a client class that can be simply used to establish the connection and receive updates. Here is a snippet of code, from the downloadable source, that show how to complete this task:

   1: /// <summary>
   2: /// Starts this instance.
   3: /// </summary>
   4: public static void Start()
   5: {
   6:     CustomBinding binding = new CustomBinding(
   7:         new PollingDuplexBindingElement(),
   8:         new BinaryMessageEncodingBindingElement(),
   9:         new HttpTransportBindingElement());
  10:  
  11:     TimeServiceClient client = new TimeServiceClient(binding, GetEndPoint());
  12:     
  13:     client.UpdateReceived += new EventHandler<UpdateReceivedEventArgs>(client_UpdateReceived);
  14:     client.RegisterAsync();
  15: }

In this few lines of code the TimeServiceClient is created. This client has to be setup with a binding compatible with the binding exposed by the server. In this case we need a custom binding using the new binary XML through the BinaryMessageEncodingBindingElement. The other element used establish a PollingDuplex channel over an http transport.

The other lines of code attach an Update event (exposed by the CallbackContract interface) and then calls the Register method (exposed by the ServiceContract) to start the polling. When this method completes - and we have an event available to check about his completion - the channel is up and running. Every time an update is available the UpdateReceived event will be raised and we may update the interface according to this data.

On the client the work is done. There is no need to have threads and all the received updates are always marshaled to the UI thread context so it is possible to update directly the User Interface.

In this sample we will simulate a timetable that show incoming races on a bus stop. When a bus is arriving to the stop the server will update the connected clients that will shows the times on the Silverlight scene. In this scenario we need to have very quicly updates and to minimize the traffic and the server work.

Creating a WCF Polling Server

The server side of the polling channel is slightly more complicated. This is not due to complexity of the PollingDuplex channel, but due to the needs to maintain trace of the registered clients and to notify them every time an update is available.

A polling duplex channel is made of two contracts instead of the usual one of normal WCF services. The first contract represent the normal ServiceContract that expose the ServiceOperations available to be called. On the other way we need to have a CallbackContract that say how a server can call on a client when an update is available and needs to notify it.

When a client connect to the service, using the Register method, the service itself will ask the OperationContext about the CallbackContract available over the client. An instance of the contract, returned by the GetCallbackChannel<T>() method will be retained by the service and used whenever it need to notify clients. Mantaining this instances needs to manage a shared collection of items and syncronize access to the elements using a lock statement. This is required because when a service instance has been created it is shared by all the calls that the service handles. So in a multi threaded environment like the context of a running webserver we have to keep in mind that the concurrency on the client callbacks contracts can affect the performances of out system.

In the sample attached to this article this responsability is of the TimeRunner class that handles the clinet collection and manage locks:

   1: /// <summary>
   2: /// Registers the specified client.
   3: /// </summary>
   4: /// <param name="client">The client.</param>
   5: public static void Register(ITimeServiceClient client)
   6: {
   7:     lock (lockObj)
   8:     {
   9:         TimeClient timeClient = new TimeClient(client);
  10:         timeClient.Fault += new EventHandler(timeClient_Fault);
  11:         TimeRunner.Clients.Add(timeClient);
  12:  
  13:         // ... omissis ...
  14:     }
  15: }

Another responsibility we have on the server side is the management of the client Fault states. A fault is the condition we may encounter when trying to send and update to a callback we get an exception because the client has been closed. There is no way to be notified about client disconnection so the only way to get rid of this problem is catching exceptions during an update. For each client connected to the service it will create an instance of a TimeClient class. This class checks the fault states when a client is updating and raise an event that signal to the TimeRunner the needs of remove the TimeClient instance from the collection:

   1: /// <summary>
   2: /// Handles the Fault event of the timeClient control.
   3: /// </summary>
   4: /// <param name="sender">The source of the event.</param>
   5: /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
   6: private static void timeClient_Fault(object sender, EventArgs e)
   7: {
   8:     lock (lockObj)
   9:     {
  10:         TimeClient timeClient = (TimeClient)sender;
  11:         TimeRunner.Clients.Remove(timeClient);
  12:         timeClient.Dispose();
  13:     }
  14: }

Let doing something...

Now that the service communication layer has been prepared to handle multiple incoming requests and updates we need to proceed start doing something in the service. While a normal WCF service simply handle calls from the web to do its work syncronous with the client, a Duplex service has to act as a worker thread that get notifications about the monitored resource and then contact the clients to send updates. The worker thread can wait for a database table to be updated, or can wait for other incoming event. In my sample I use a FileSystemWatcher to monitor changes to an xml file. The timetable.xml file contains sample data about races passing in a bus stop. I imagined that a windows service is collecting informations about the bus running ina town and when it have updates simply write to a xml file. This writing is catched by the FileSystemWatcher and notify the WCF duplex service thread. The notification received by the service cause the timetable to be loaded and a diffgram is send to the connected clients.

   1: /// <summary>
   2: /// Handles the Changed event of the Watcher control.
   3: /// </summary>
   4: /// <param name="sender">The source of the event.</param>
   5: /// <param name="e">The <see cref="System.IO.FileSystemEventArgs"/> instance containing the event data.</param>
   6: private static void Watcher_Changed(object sender, FileSystemEventArgs e)
   7: {
   8:     RacesTable table = LoadRaces();
   9:  
  10:     RaceUpdate update = new RaceUpdate
  11:     {
  12:         AddedOrModified = (from upd in table.Races
  13:                            where !TimeRunner.CurrentTable.Races.Contains(upd)
  14:                            select upd).ToArray(),
  15:         Deleted = (from old in TimeRunner.CurrentTable.Races
  16:                    where !table.Races.Select(rc => rc.UniqueID).Contains(old.UniqueID)
  17:                    select old).ToArray()
  18:     };
  19:  
  20:     lock (lockObj)
  21:     {
  22:         for(int i=0; i<TimeRunner.Clients.Count; i++)
  23:         {
  24:             TimeClient client = TimeRunner.Clients[i];
  25:             if (!client.IsSending) client.Send(update);
  26:         }
  27:     }
  28:  
  29:     TimeRunner.CurrentTable = table;
  30: }

The diffgram is calculated using an image of the timetable in memory that contains the latest version of the file. The new file and the old image is compared using linq and the diffgram is created with Added, Modified and Deleted items. The client that receive this update simply apply this changes tho his own copy of the timetable. The only exception to this flow happen when a client connect . In this case it get the complete content of the timetable from the memory of the service.

Hosting service and serving policies

A duplex service may be hosted by Internet Information Service, by a windows service or by a simple console application. In this example I choose to use a console application to maintain the source code simple. While using the IIS as host allow to serve clientaccesspolicy.xml files in a simple way, using a windows process needs to implements some tricks to serve this file as we did if we have a webserver. To do this I've implemented an endpoint using the webHttpBinding and return the xml file when it is requested. For more detail on this tecnique please read this .

Now that the sample has been described you may run it by yourself. Firts of all you need to run the service application and then starts the web application containing the Silverlight xap.

Download: Elite.Silverlight3.Polling.zip (1,4 MB)
Categories:   Networking
Actions:   E-mail | del.icio.us | Permalink | Comments (18) | Comment RSSRSS comment feed

A proxy class to tunnel Socket channels

2009-04-01T23:00:00+01:00 by Andrea Boschin

One of the requests I found, following the Silverlight forums, is the capability to connect a Socket to an arbitrary port out of the restricted range where Silverlight is allowed to work. Since the release 2.0, Silverlight is allowed to connect to the network using a Socket but has a limitation that forbid the access to ports out of the range from 4502 to 4534. Another requirements for the sockets to work is that the same service must expose a clientaccesspolicy.xml file on a well known port 943 stating the ports opened by the service.

This complicated context let the use of the Sockets difficult and limitated to custom services. The limit of 32 ports opened is fine if someone has to create a custom service giving realtime updates, but is frustrating if the need is to access a well know network service like DNS, Telnet and other. We have to know that some network protocols are impossible to be implemented with Silverlight because of them nature. Thinking about FTP the duplex nature of this service, where server and client exchange their role (the client become server when receiving a file)  let this protocol impossible to be implemented in Silverlight where there is no way to listen to incoming connections. There is a number of other existing services, and often a number of existing custom services that rely on ports out of the 4502-4534 range and that we would like to consume without changing the code because often they are already published to other systems.

In this article I will explain a simple project I've implemented to let some services to be "tunneled" moving their original port to another port in the range allowed to Silverlight. This service that is freely downloadable at the end of the post, also implements a channel on the port 943 to allow Silverlight to get the client access policies before to connect to the tunneled ports.

The system Architecture

Before showing some snippets of code I will try to explain how my solution works. I will go through the architecture showing the components and the reason of my choice. The first concept you may know about implementing Sockets is that when you are listening on a port you are waiting for accepting clients and when a client connect you need to start a thread that take the accepted client and manage it separately from the main listening socket. This behavioh allow you to manage multiple incoming clients giving each connection in charge to a separate thread and leaving the port free to return a the listening task. Another requirement we have developing the solution for Silverlight is to have two servers listening, one for the policy distribution and the other on the proxy service that forward traffic to the required port.

To solve this problem I've created a base class ThreadedObject that implements the base behavior of every subsystem. From this class I've inherited three types that manage the different parts of the problem.

classes

The ThreadedObject class is in charge of managing the lifetime of the thread. It is a IDisposable class so it is created with an using construct and this cause the closing of the thread when the class goes out of scope. The trick is the usage of a ManualResetEvent exposed to the subclasses. When this event will be set the thread has to exit gracefully.

The SocketProxy class

This class have in charge the task to listen for incoming connections on both the policy port 943 and the proxy channel that we will expose on the port 4530. I've created this class thinking about a developer that needs to embed a listening proxy in a Windows service. It is a simple class that request a few parameters in input and when started run a thread that listen. As you may know the parameters tells the host and the ports where to listen and forward connections. In my solution this parameters are read from the app.config file. The constructor wants also the path of a policy file. Here is the main thread procedure of the class:

   1: /// <summary>
   2: /// Listen the thread.
   3: /// </summary>
   4: /// <param name="state">The state.</param>
   5: protected override void ThreadProc()
   6: {
   7:     IPHostEntry hostEntry = Dns.GetHostEntry(this.ListenHost);
   8:     IPAddress ipAddress = hostEntry.AddressList.Where(entry => entry.AddressFamily == AddressFamily.InterNetwork).FirstOrDefault();
   9:  
  10:     if (ipAddress != null)
  11:     {
  12:         this.PolicyListener = new TcpListener(ipAddress, 943);
  13:         this.PolicyListener.Start();
  14:         this.ProxyListener = new TcpListener(ipAddress, this.ListenPort);
  15:         this.ProxyListener.Start();
  16:  
  17:         while (WaitHandle.WaitTimeout == WaitHandle.WaitAny(this.ExitHandles, 10))
  18:         {
  19:             if (this.PolicyListener.Pending())
  20:             {
  21:                 PolicyClient policyClient =
  22:                     new PolicyClient(this.PolicyListener.AcceptTcpClient(), this.PolicyFile);
  23:                 policyClient.Start();
  24:  
  25:             }
  26:             else if (this.ProxyListener.Pending())
  27:             {
  28:                 ProxyClient proxyClient = 
  29:                     new ProxyClient(this.ProxyListener.AcceptTcpClient(), this.TargetHost, this.TargetPort);
  30:                 proxyClient.Start();
  31:             }
  32:         }
  33:     }
  34:     else
  35:         throw new ApplicationException(Resources.CannotResolveAddress);
  36: }

The class starts two instances of TcpListener and then poll the Pending() method to check when there is waiting clients to accept. When a client is ready it starts an instance of the managing type.

The PolicyClient

This class implements a manager for the clients requesting the policies. It will be started by the SocketProxy class when a client ask for a connection. The class operate in two steps: first of all it wait for the client to send the policy request string then it sends the policy file and finally close the connection:

   1: /// <summary>
   2: /// Threads the proc.
   3: /// </summary>
   4: protected override void ThreadProc()
   5: {
   6:     try
   7:     {
   8:         while (WaitHandle.WaitTimeout == WaitHandle.WaitAny(this.ExitHandles, 10) &&
   9:             this.Client.Available == 0) ;
  10:  
  11:         ReadAndSend();
  12:     }
  13:     finally
  14:     {
  15:         this.Client.Close();
  16:     }
  17: }
  18:  
  19: /// <summary>
  20: /// Validates the and send.
  21: /// </summary>
  22: /// <returns></returns>
  23: private void ReadAndSend()
  24: {
  25:     NetworkStream stream = this.Client.GetStream();
  26:  
  27:     byte[] data = new byte[PolicyRequestString.Length];
  28:     stream.Read(data, 0, data.Length);
  29:  
  30:     string readString = Encoding.UTF8.GetString(data);
  31:  
  32:     if (readString == PolicyRequestString)
  33:     {
  34:         stream.Write(this.PolicyFile, 0, this.PolicyFile.Length);
  35:         stream.Flush();
  36:     }
  37: }

The class request in the constructor a byte array of the policy file to send. This buffer is loaded by the SocketProxy class and then decoded to a byte array and passed to all the instances.

The ProxyClient

This is the most critical class that have in charge the clients when tunneling the traffic in both the directions. It will have two clients; the silverlight part and the tunneled service part. It simply wait for traffic from each client and forward it to the other. The operation of tunneling the data is the critical part. I read the data from a channel in 1024 bytes chunks and write the same bytes on the other client. I think this part has to be tested on various services and tuned finding the best strategy. The current implementation may fail when both parts of the channel is data intensive because reading data from a channel stops reading data from the other.

   1: /// <summary>
   2: /// Threads the proc.
   3: /// </summary>
   4: protected override void ThreadProc()
   5: {
   6:     try
   7:     {
   8:         while (WaitHandle.WaitTimeout == WaitHandle.WaitAny(this.ExitHandles, 10) &&
   9:             this.Client.Available == 0) ;
  10:  
  11:         ReadAndSend();
  12:     }
  13:     finally
  14:     {
  15:         this.Client.Close();
  16:     }
  17: }
  18:  
  19: /// <summary>
  20: /// Validates the and send.
  21: /// </summary>
  22: /// <returns></returns>
  23: private void ReadAndSend()
  24: {
  25:     NetworkStream stream = this.Client.GetStream();
  26:  
  27:     byte[] data = new byte[PolicyRequestString.Length];
  28:     stream.Read(data, 0, data.Length);
  29:  
  30:     string readString = Encoding.UTF8.GetString(data);
  31:  
  32:     if (readString == PolicyRequestString)
  33:     {
  34:         stream.Write(this.PolicyFile, 0, this.PolicyFile.Length);
  35:         stream.Flush();
  36:     }
  37: }

Testing the application

To test the class I've selected a service from the canonical ports exposed by a system.  Finally I've selected the daytime port 13. It is a service that on Windows has to be installed under the Simple TCP services and then started by the Services applet. The choice of this simple and slightly unuseful ports is only to give a very simple example that show how to expose a port that is really out of the Silverlight range. My simple application has a button and a TextBlock. When the Button is clicked a Socket connection will be made to appthe daytime service and the returned system time will be displayed in the TextBlock.

The server part is configured to tunnel connection incoming on port 4530 to the system dtaytime port and to serve a policy file from the file system.

I'm thinking to write a more powerful sample on this code. Opening ports to the silverlight applications may open a wide range of solutions limited only by your creativity and probably by your it manager. When exposing a port on the internet you have to concern about security issues. Every opened port to the network is a potential security disclosure but the security must be implemented in the protocol you are exposing. Also you have to know that exposing a well-know port may give an opportunity to use a well know bug to enter your system.

Download: Elite.Silverlight.SocketProxy.zip (1,1 MB)

Silverlight 3.0: Local Connections

2009-03-18T18:44:00+01:00 by Andrea Boschin

More than often working with Silverlight you may want to communicate from a plugin instance to another instance in the same page. Coordinating scenes, across different plugin instances, may be a difficult issue with Silverligth 2.0, involving HTML Bridge and often limitated because this bridge needs to be enabled. With the recently released version 3.0 beta 1 working in this way it is simple like drinking a glass of water thanks to a new feature called Local Connection.

What is a Local Connection?

The new Silverlight 3.0 allow the plugin to expose a listener, with a specific name, that may be addresses by other plugin instances knowing this name. If you had ever used named-pipes for inter process communications you may found that Local Connections are very similar. There are two classes you may use to establish a connection; LocalMessageReceiver and LocalMessageSender. The first one is used to expose an endpoint with this few lines of code:

   1: LocalMessageReceiver receiver = new LocalMessageReceiver(name);
   2: receiver.MessageReceived += new EventHandler<MessageReceivedEventArgs>(Receiver_MessageReceived);
   3: receiver.Listen();

The "name" used when you create the instance of the receiver is the name you have to use when you create the LocalMessageSender. Here is how to create a sender in a remote plugin. The sender needs simply to be instantiated and is ready to send messages. The most beautiful thing is that a couple of Received and Sender may communicate across plugins not always in the same page but also across plugins instantiated in different browsers.

Here is how to instantiate the LocalMessageSender and send a message to a listening receiver:

   1: LocalMessageSender sender = new LocalMessageSender(name);
   2: sender.SendAsync("this is a message");

Obviously the receiver must exist and listening. The messages you may exchange over this channel are plain strings so if you have to send complex informations you have to create a private protocol wrapping this data. As an example you may use JSON or XML Serializer to send class instances to another plugin.

A live example

We have now to create a working example of this tecnique, so let' try to coordinate the movement of one element across four instances, disposed to compose a square. We call this instances with a name, that will be the name of the listening channel and identify the position the plugin assume in the square. the names are "nw", "ne", "sw" and "se" like the cardinal directions.

image

With a good design we create a class "Communicator" that encapsulate the communicationg channel and expose a method Move() called to move the element on all the listening instances and an event "PositionChanged" that notify to the user interface that the elements position needs to be changed. The Communicator class instance a single LocalMessageReceiver with the name of the local plugin a three LocalMessageSender named with the names of the other plugins.

   1: private List<LocalMessageSender> Senders { get; set; }
   2: private LocalMessageReceiver Receiver { get; set; }
   3:  
   4: public Communicator(string name, IEnumerable<string> clients)
   5: {
   6:     this.Receiver = new LocalMessageReceiver(name);
   7:     this.Receiver.MessageReceived += new EventHandler<MessageReceivedEventArgs>(Receiver_MessageReceived);
   8:     this.Receiver.Listen();
   9:  
  10:     this.Senders = new List<LocalMessageSender>();
  11:  
  12:     foreach (string client in clients)
  13:         this.Senders.Add(new LocalMessageSender(client));
  14: }

 

Now that we have created the channels to allow the position exchange we have to plan how to exchange the position coordinates. X and Y position wil be transmitted in a pipe-separated string. Deserializing this string imply to split the string in two parts and create a Point instance with the double values parsed in the strings. In the MessageReceived event we raise the PositionChanged event deserializing the incoming message and forwarding the point to the UI to apply it to a translate transform the shift the graphical element on the plugin area.

   1: public event EventHandler<PositionChangedEventArgs> PositionChanged;
   2:  
   3: private void Receiver_MessageReceived(object sender, MessageReceivedEventArgs e)
   4: {
   5:     string[] coords = e.Message.Split('|');
   6:  
   7:     this.OnPositionChanged(
   8:         new Point(double.Parse(coords[0]), double.Parse(coords[1])));
   9: }
  10:  
  11: protected virtual void OnPositionChanged(Point point)
  12: {
  13:     EventHandler<PositionChangedEventArgs> handler = this.PositionChanged;
  14:  
  15:     if (handler != null)
  16:         handler(this, new PositionChangedEventArgs(point));
  17: }

In the Move() method we have to perform two actions. The first action serialize the Point to a string and send it to other plugins using the SendAsync() method. The message is delivered to the receivers that will execute the MessageReceived event code. The second action we have to perform is raising a local PositionChanged event to update the position of the local element:

   1: public void Move(Point point)
   2: {
   3:     string message = string.Format("{0}|{1}", point.X, point.Y);
   4:  
   5:     foreach (LocalMessageSender sender in this.Senders)
   6:         sender.SendAsync(message);
   7:  
   8:     this.OnPositionChanged(point);
   9: }

Now that the Communicator class is ready we have simply to wrap mouse events to handle dragging inside a plugin. This is a simple task using MouseLeftButtonDown, MouseLeftButtonUp and MouseMove. The Loaded event evaluate the name of the plugin and initially move the element in a particular position to let it appear the same under the plugins. Using a translate transform allow to exchange coordinated that are the same on all the instances so we do not need to apply any calculation. Here is the code:

   1: private void LayoutRoot_MouseMove(object sender, MouseEventArgs e)
   2: {
   3:     // if StartPoint is not null the Mouse button is pressed
   4:     if (this.StartPoint.HasValue)
   5:     {
   6:         Point position = e.GetPosition(this.LayoutRoot);
   7:  
   8:         double x = this.StartTransform.Value.X + position.X - this.StartPoint.Value.X;
   9:         double y = this.StartTransform.Value.Y + position.Y - this.StartPoint.Value.Y;
  10:  
  11:         this.Communicator.Move(new Point(x, y));
  12:     }
  13: }
  14:  
  15: private void Communicator_PositionChanged(object sender, PositionChangedEventArgs e)
  16: {
  17:     transform.X = e.Point.X;
  18:     transform.Y = e.Point.Y;
  19: }

As you may see the incoming message is applied to the transformation. In this way the element appear to move on all the instances in the same moment. To have a try of this effect simply click this link and drag with the mouse into each circle. You will see the element moving in each plugin instance at the same time giving a strange effect.

But the best demostration is to open every instance in a new browser window. If you assign at every new window the correct string "nw", "ne", etc... you may move the element in a windows and you will see the same elements moving in the other windows. Local connections are capable to communicate also throught different browser instances.

I think this new feature is really interesting. I may imagine a couple of ways to use Local connections, but I leave to your fantasy to discover new useful scenarion where you may apply this tecnique.

Download Code: (856 KB)

Demo Video: (1.9 MB)