Author: Giovanni Montrone Difficulty: Intermediate Time Required: 5-10 hours Cost: Free Software: Visual Web Developer Express SP1 (or Visual Studio 2008 SP1), Silverlight 3 SDK , Silverlight 3 Tools for VS , Silverlight Toolkit Hardware: None Use it Now: Run the Application Source Download: CodePlex Introduction Every once in a while I will run into a situation where I need to send a file to someone, but struggle to find an easy way of doing it. Instant messenger programs usually work until you run into a situation where someone just cannot send or receive a file from chat client whether it’s due to firewalls, differing client versions, or multi-IM incompatibilities. Other times, I will try to send the file via email just to find out that the person’s email server blocks specific extensions. This quick application will allow two users to quickly and easily connect to a Silverlight 3 client and send each other files. Overview In this application, a user will connect to the Silverlight application and choose to either host or join a session. If a user decides to host a session, he or she will be given a random eight character session key, and he or she will be in a waiting status until another user connects. When a user wishes to connect to the host, he or she can supply the host’s session key which will establish a connection between the two users. Once connected, the users will be able to send files to one another, and will also be able to chat with each other via simple text messages. Polling Duplex Sending a file from one client application to another requires a common central point in order to properly route the message from one user to another. Since it is easy to host a Silverlight application in an ASP.NET page, we will use an ASP.NET back end to manage all communications between all connected users. In order to do this, we must be able to host a service that is able to accept incoming messages from the Silverlight client, and perform a push back out to the intended recipient. This is accomplished by using the WCF Polling Duplex ( System.ServiceModel.PollingDuplex.dll ) channel. Silverlight 3 allows us to directly add a service reference to a service of this type, and handles all of the complexities for us. I began by using the DuplexService.cs file from a sample application from MIX09 when Silverlight 3 beta was released. The code starts us out with a couple of base abstract classes, and interfaces that we must inherit from in order to create our own service. FileSendService The two main things we need to do in order to create our own service is to define custom message types that will be used for communication, and override the base DuplexService class to properly handle these messages. We will create our custom message types by using DuplexMessage (defined in DuplexService.cs ) as our base class. Our message classes must be defined with the [DataContract] attribute, and the the member variables must be public and contain the [DataMember] attribute. This will allow our Silverlight client project to share these definitions using a service reference. Additionally, the Duplex message class must have the [KnownType] attribute for each descendant message created. C# [KnownType( typeof (HostSessionMessage))] [KnownType( typeof (JoinSessionMessage))] [KnownType( typeof (FileBeginUploadMessage))] [KnownType( typeof (FileTransferBytesMessage))] public class DuplexMessage { } [DataContract] public class HostSessionMessage : DuplexMessage { [DataMember] public string Username; } [DataContract] public class JoinSessionMessage : DuplexMessage { [DataMember] public string Username; [DataMember] public string SessionKey; } [DataContract] public class FileBeginUploadMessage : DuplexMessage { [DataMember] public string FileName; [DataMember] public long TotalBytes; } [DataContract] public class FileTransferBytesMessage : DuplexMessage { [DataMember] public long StartByte; [DataMember] public long PacketSize; [DataMember] public byte [] Bytes; [DataMember] public bool EndFile; } VB <DataContract( Namespace := "http://samples.microsoft.com/silverlight2/duplex" ), KnownType( GetType (HostSessionMessage)), KnownType( GetType (JoinSessionMessage)), KnownType( GetType (FileBeginUploadMessage)), KnownType( GetType (FileTransferBytesMessage))> _ Public Class DuplexMessage End Class <DataContract()> _ Public Class HostSessionMessage Inherits DuplexMessage <DataMember()> Public Username As String End Class <DataContract()> _ Public Class JoinSessionMessage Inherits DuplexMessage <DataMember()> Public Username As String <DataMember()> Public SessionKey As String End Class <DataContract()> _ Public Class FileTransferBytesMessage Inherits DuplexMessage <DataMember()> Public StartByte As Long <DataMember()> Public PacketSize As Long <DataMember()> Public Bytes() As Byte <DataMember()> Public EndFile As Boolean End Class <DataContract()> _ Public Class FileBeginUploadMessage Inherits DuplexMessage <DataMember()> Public FileName As String <DataMember()> Public TotalBytes As Long End Class The next step is to create our FileSendService class which descends from the DuplexService class as described above. We override the OnMessage method so that we can do custom processing based on the type of message sent as shown below. C# [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class FileSendService : DuplexService { private List<SessionConnectionInfo> sessionConnections = new List<SessionConnectionInfo>(); {…} protected override void OnMessage( string sessionId, DuplexMessage data) { if (data is HostSessionMessage) CreateHostSession(data as HostSessionMessage); else if (data is JoinSessionMessage) JoinSession(data as JoinSessionMessage); else if (data is FileBeginUploadMessage) StartSendFile(data as FileBeginUploadMessage); else SendMessage(data); } } else if (data is JoinSessionMessage) JoinSession(data as JoinSessionMessage); else if (data is FileBeginUploadMessage) StartSendFile(data as FileBeginUploadMessage); else SendMessage(data); } } } } VB Public Class FileSenderServiceFactory Inherits DuplexServiceFactory(Of FileSendService) End Class <AspNetCompatibilityRequirements(RequirementsMode := AspNetCompatibilityRequirementsMode.Allowed)> _ Public Class FileSendService Inherits DuplexService Private sessionConnections As New List(Of SessionConnectionInfo)() ..