What If I Don’t Call Dispose() on my LINQ to SQL DataContext Object?

Posted on August 20, 2008 by dwahlin.
Categories: C#, Contributors.

I’ve written a few posts about LINQ to SQL and am generally a big fan of the technology (even with its weaknesses) since it’s very productive.  After creating a custom DataContext object using the LINQ to SQL designer (or one created by hand) I always ensure that the object is wrapped in a “using” statement so that the Dispose() method is called:

  1. using (MyDataContext context = new MyDataContext())
  2. {
  3. <br>    //Perform query
  4. }

I had assumed that not properly disposing of the DataContext object would lead to orphan SQL connections which is of course bad and will likely lead to your DBA holding a grudge against you for life. :-)

Steven Walther recently posted on the subject of disposing of DataContext objects and provided some interesting insight into what actually happens.  From what he says it sounds like the DataContext object acts much like the SqlDataAdapter class.  It opens the connection right before a query is executed and closes it immediately after.  I don’t want to steal Steven’s thunder so check out his post on the subject (the last part of the article talks about the consequences…or lack of consequences…of not calling Dispose()). 

I haven’t had time to verify the details in Reflector yet, but given that Steven’s one of the more intelligent people I know I’m confident that the details he presents are accurate.  It still feels more correct to wrap “using” statements around any object that implements IDisposable or explicitly call Dispose() in my opinion, but it’s good to know how the DataContext object works behind the scenes.

Pushing Data to a Silverlight Client with a WCF Duplex Service – Part II

Posted on June 19, 2008 by dwahlin.
Categories: C#, Contributors, Silverlight.
In Part 1 of this series on pushing data to a Silverlight client with a WCF polling duplex service I demonstrated how service contracts and operations can be defined on the server.  WCF has built-in support for duplex communication (two-way communication between a service and a client) but does require a reference to System.ServiceModel.PollingDuplex.dll to make it work with Silverlight.  This assembly is provided in the Silverlight SDK and is currently in “evaluation” mode (the Silverlight go-live license doesn’t apply to it).  With the polling duplex model the Silverlight client does poll the service to check if any messages are queued so it’s not as “pure” as the sockets option available in Silverlight when it comes to pushing data from a server to a client.  However, it offers much greater flexibility when compared to sockets since it isn’t limited to a specific port range and works over HTTP. Let’s take a look at how a Silverlight client can send and receive messages from a polling duplex WCF service and what types of messages are sent between the two.

Understanding Polling Duplex Messages

A polling duplex service communicates with a Silverlight client using WCF Message types.  This provides complete control over the data sent between the client and the service and allows communication between the two to be loosely coupled.  The downside of this is that messages must be manually serialized/deserialized by the client and service since the WSDL type information uses the xs:any element.  Here’s what the service’s WSDL types section looks like (notice the inclusion of the xs:any element) when a service uses the Message type as a parameter for an operation:
  1. <xs:schema elementFormDefault="qualified" targetNamespace="http://schemas.microsoft.com/Message" xmlns:xs="http://www.w3.org/2001/XMLSchema"
  2.   xmlns:tns="http://schemas.microsoft.com/Message">
  3. <xs:complexType name="MessageBody">
  4.   <xs:sequence>
  5.     <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##any"/>
  6.   </xs:sequence>
  7. </xs:complexType>
  8. </xs:schema>
An example of using the WCF Message type in a WCF service is shown next.  Details about this code were covered in Part I of this series.
  1. using System;
  2. using System.ServiceModel;
  3. using System.ServiceModel.Channels;
  4. using System.Threading;
  5.  
  6. namespace WCFPushService
  7. {
  8.     public class GameStreamService : IGameStreamService
  9.     {
  10.         IGameStreamClient _Client;
  11.         Game _Game = null;
  12.         Timer _Timer = null;
  13.         Random _Random = new Random();
  14.  
  15.         public GameStreamService()
  16.         {
  17.             _Game = new Game();
  18.         }
  19.  
  20.         public void GetGameData(Message receivedMessage)
  21.         {
  22.  
  23.             //Get client callback channel
  24.             _Client = OperationContext.Current.GetCallbackChannel&lt;IGameStreamClient&gt;();
  25.  
  26.             SendData(_Game.GetTeamData());
  27.             //Start timer which when fired sends updated score information to client
  28.             _Timer = new Timer(new TimerCallback(_Timer_Elapsed), null, 5000, Timeout.Infinite);
  29.         }
  30.  
  31.         private void _Timer_Elapsed(object data)
  32.         {
  33.             SendData(_Game.GetScoreData());
  34.             int interval = _Random.Next(3000, 7000);
  35.             _Timer.Change(interval, Timeout.Infinite);
  36.         }
  37.  
  38.         private void SendData(object data)
  39.         {
  40.             Message gameDataMsg = Message.CreateMessage(
  41.                 MessageVersion.Soap11,
  42.                 "Silverlight/IGameStreamService/ReceiveGameData", data);
  43.  
  44.             //Send data to the client
  45.             _Client.ReceiveGameData(gameDataMsg);
  46.         }
  47.     }
  48. }

Creating a Silverlight Duplex Polling Receiver Class

Calling and receiving data in Silverlight requires a fair amount of code to be written.  Before showing the code to interact with a polling duplex service it’s important to understand the general steps involved.  Here’s what you need to do to send and receive data in a Silverlight client: Reference Assemblies and Namespaces
  1. Reference System.ServiceModel.dll and System.ServiceModel.PollingDuplex.dll in your Silverlight project.  Additional details on where to find the System.ServiceModel.PollingDuplex.dll assembly used by Silverlight can be found here.
  2. Import the System.ServiceModel and System.ServiceModel.Channels namespaces.
Create a Factory Object
  1. Create a PollingDuplexHttpBinding object instance and set the PollTimeout and InactivityTimeout properties (both were discussed in Part 1).
  2. Use the PollingDuplexHttpBinding object to build a channel factory.
  3. Open the channel factory and define an asynchronous callback method that is called when the open completes.
Create a Channel Object
  1. Use the factory class to create a channel that points to the service’s HTTP endpoint.
  2. Open the channel and define an asynchronous callback method that is called when the open completes.
  3. Define a callback method that is called when the channel closes.
Send/Receive Messages
  1. Create a Message object and send it asynchronously to the service using the channel object.  Define an asynchronous callback method that is called when the send completes.
  2. Start a message receive loop to listen for messages “pushed” from the service and define a callback method that is called when a message is received.
  3. Process data pushed by the server and dispatch it to the Silverlight user interface for display.
Now that you’ve seen the fundamental steps, let’s take a look at the code that makes this process work.  The following code shows a class named PushDataReceiver that encapsulates the factory and channel classes and handles all of the asynchronous operations that occur.  The class allows an object of type IProcessor to be passed into it along with a service URL, service action and initial data to send to the service (if any).  The IProcessor object represents the actual Silverlight Page class used to update data on the user interface in this case.  As data is received the Page class’s ProcessData() method will be called.
  1. using System;
  2. using System.Net;
  3. using System.ServiceModel;
  4. using System.ServiceModel.Channels;
  5. using System.Threading;
  6. using System.IO;
  7. using System.Xml.Serialization;
  8.  
  9. namespace SilverlightPushClient
  10. {
  11.     public interface IProcessor
  12.     {
  13.         void ProcessData(object receivedData);
  14.     }
  15.  
  16.     public class PushDataReceiver
  17.     {
  18.         SynchronizationContext _UiThread = null;
  19.         public IProcessor Client { get; set; }
  20.         public string ServiceUrl { get; set; }
  21.         public string Action { get; set; }
  22.         public string ActionData { get; set; }
  23.  
  24.         public PushDataReceiver(IProcessor client, string url, string action, string actionData)
  25.         {
  26.             Client = client;
  27.             ServiceUrl = url;
  28.             Action = action;
  29.             ActionData = actionData;
  30.             _UiThread = SynchronizationContext.Current;
  31.         }
  32.  
  33.         public void Start()
  34.         {
  35.             // Instantiate the binding and set the time-outs
  36.             PollingDuplexHttpBinding binding = new PollingDuplexHttpBinding()
  37.             {
  38.                 PollTimeout = TimeSpan.FromSeconds(10),
  39.                 InactivityTimeout = TimeSpan.FromMinutes(1)
  40.             };
  41.  
  42.             // Instantiate and open channel factory from binding
  43.             IChannelFactory&lt;IDuplexSessionChannel&gt; factory =
  44.                 binding.BuildChannelFactory&lt;IDuplexSessionChannel&gt;(new BindingParameterCollection());
  45.  
  46.             IAsyncResult factoryOpenResult =
  47.                 factory.BeginOpen(new AsyncCallback(OnOpenCompleteFactory), factory);
  48.             if (factoryOpenResult.CompletedSynchronously)
  49.             {
  50.                 CompleteOpenFactory(factoryOpenResult);
  51.             }
  52.         }
  53.  
  54.         void OnOpenCompleteFactory(IAsyncResult result)
  55.         {
  56.             if (result.CompletedSynchronously)
  57.                 return;
  58.             else
  59.                 CompleteOpenFactory(result);
  60.         }
  61.  
  62.         void CompleteOpenFactory(IAsyncResult result)
  63.         {
  64.             IChannelFactory&lt;IDuplexSessionChannel&gt; factory =
  65.                 (IChannelFactory&lt;IDuplexSessionChannel&gt;)result.AsyncState;
  66.  
  67.             factory.EndOpen(result);
  68.  
  69.             // The factory is now open. Create and open a channel from the channel factory.
  70.             IDuplexSessionChannel channel =
  71.                 factory.CreateChannel(new EndpointAddress(ServiceUrl));
  72.  
  73.             IAsyncResult channelOpenResult =
  74.                 channel.BeginOpen(new AsyncCallback(OnOpenCompleteChannel), channel);
  75.             if (channelOpenResult.CompletedSynchronously)
  76.             {
  77.                 CompleteOpenChannel(channelOpenResult);
  78.             }
  79.         }
  80.  
  81.         void OnOpenCompleteChannel(IAsyncResult result)
  82.         {
  83.             if (result.CompletedSynchronously)
  84.                 return;
  85.             else
  86.                 CompleteOpenChannel(result);
  87.         }
  88.  
  89.         void CompleteOpenChannel(IAsyncResult result)
  90.         {
  91.             IDuplexSessionChannel channel = (IDuplexSessionChannel)result.AsyncState;
  92.  
  93.             channel.EndOpen(result);
  94.  
  95.             // Channel is now open. Send message
  96.             Message message =
  97.                 Message.CreateMessage(channel.GetProperty&lt;MessageVersion&gt;(),
  98.                  Action , ActionData);
  99.             IAsyncResult resultChannel =
  100.                 channel.BeginSend(message, new AsyncCallback(OnSend), channel);
  101.             if (resultChannel.CompletedSynchronously)
  102.             {
  103.                 CompleteOnSend(resultChannel);
  104.             }
  105.  
  106.             //Start listening for callbacks from the service
  107.             ReceiveLoop(channel);
  108.         }
  109.  
  110.         void OnSend(IAsyncResult result)
  111.         {
  112.             if (result.CompletedSynchronously)
  113.                 return;
  114.             else
  115.                 CompleteOnSend(result);
  116.         }
  117.  
  118.         void CompleteOnSend(IAsyncResult result)
  119.         {
  120.             IDuplexSessionChannel channel = (IDuplexSessionChannel)result.AsyncState;
  121.             channel.EndSend(result);
  122.         }
  123.  
  124.         void ReceiveLoop(IDuplexSessionChannel channel)
  125.         {
  126.             // Start listening for callbacks.
  127.             IAsyncResult result = channel.BeginReceive(new AsyncCallback(OnReceiveComplete), channel);
  128.             if (result.CompletedSynchronously) CompleteReceive(result);
  129.         }
  130.  
  131.         void OnReceiveComplete(IAsyncResult result)
  132.         {
  133.             if (result.CompletedSynchronously)
  134.                 return;
  135.             else
  136.                 CompleteReceive(result);
  137.         }
  138.  
  139.         void CompleteReceive(IAsyncResult result)
  140.         {
  141.             //A callback was received so process data
  142.             IDuplexSessionChannel channel = (IDuplexSessionChannel)result.AsyncState;
  143.  
  144.             try
  145.             {
  146.                 Message receivedMessage = channel.EndReceive(result);
  147.  
  148.                 // Show the service response in the UI.
  149.                 if (receivedMessage != null)
  150.                 {
  151.                     string text = receivedMessage.GetBody&lt;string&gt;();
  152.                     _UiThread.Post(Client.ProcessData, text);
  153.                 }
  154.  
  155.                 ReceiveLoop(channel);
  156.             }
  157.             catch (CommunicationObjectFaultedException exp)
  158.             {
  159.                 _UiThread.Post(delegate(object msg) { System.Windows.Browser.HtmlPage.Window.Alert(msg.ToString()); }, exp.Message);
  160.             }
  161.         }
  162.  
  163.         void OnCloseChannel(IAsyncResult result)
  164.         {
  165.             if (result.CompletedSynchronously)
  166.                 return;
  167.             else
  168.                 CompleteCloseChannel(result);
  169.         }
  170.  
  171.         void CompleteCloseChannel(IAsyncResult result)
  172.         {
  173.             IDuplexSessionChannel channel = (IDuplexSessionChannel)result.AsyncState;
  174.             channel.EndClose(result);
  175.         }
  176.     }
  177. }
When the PushDataReceiver class’s Start() method is called by Silverlight it creates a channel factory instance which is used to create a channel instance.  The CompleteOpenChannel() callback method shown previously then sends an initial message to the service endpoint and encapsulates the data to be sent in a WCF Message object.  The message data is then sent along with the proper service action to call on the server.  After the initial message is sent a receive loop is started (see the ReceiveLoop() method) which listens for any messages sent from the server to the client and processes them accordingly.  Once a message is received the CompleteReceive() method is called and the message data is routed back to the Silverlight Page class.

Processing Data Using the XmlSerializer Class

The PushDataReceiver class shown earlier dispatches data received from the server back to the Silverlight Page class for processing.  Data sent from the server is in XML format and multiple techniques can be used to process it in Silverlight ranging from the XmlReader class to LINQ to XML functionality to the XmlSerializer class.  I chose to use the XmlSerializer class to process the data since it provides a simple way to map XML data to CLR types with a minimal amount of code.  Although you can create the CLR classes that XML data maps to by hand, I chose to create an XSD schema and use .NET’s xsd.exe tool to generate code from the schema for me.  The xsd.exe tool provides a simple way to generate C# or VB.NET code and ensures that the XML data will be successfully mapped to the appropriate CLR type’s properties.  An example of using the tool is shown next: xsd.exe /c /namespace:SomeNamespace Teams.xsd The /c switch tells the tool to generate classes (as opposed to strongly-typed DataSets) while the /namespace switch allows you to control what namespace is added into the auto-generated code.  Other switches are available which you can read more about here. One of the XSD schemas used to generate C# code with xsd.exe is shown next:
  1. <?xml version="1.0" encoding="utf-16"?>
  2. <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  3.   <xs:element name="Teams">
  4.     <xs:complexType>
  5.       <xs:sequence>
  6.         <xs:element maxOccurs="unbounded" name="Team">
  7.           <xs:complexType>
  8.             <xs:sequence>
  9.               <xs:element maxOccurs="unbounded" name="Player">
  10.                 <xs:complexType>
  11.                   <xs:attribute name="ID" type="xs:string" use="required" />
  12.                   <xs:attribute name="Name" type="xs:string" use="required" />
  13.                 </xs:complexType>
  14.               </xs:element>
  15.             </xs:sequence>
  16.             <xs:attribute name="Name" type="xs:string" use="required" />
  17.           </xs:complexType>
  18.         </xs:element>
  19.       </xs:sequence>
  20.     </xs:complexType>
  21.   </xs:element>
  22. </xs:schema>
Note: If you use the xsd.exe tool to generate classes that will be used in a Silverlight client you’ll have to remove a few lines that don’t compile from the auto-generated code.  The xsd.exe tool generates code designed to run on the full version of the .NET framework but with a few minor modifications you can also use the code with Silverlight.  Simply remove the namespaces and attributes that the compiler says are invalid from the auto-generated code. Once data is received by the Silverlight client from the WCF polling duplex service it’s processed by a method named ProcessData() (the method called by the PushDataReceiver class) in the sample application.  ProcessData() uses the XmlSerializer class to deserialize XML data into custom Teams and ScoreData objects (the Teams and ScoreData classes were generated from XSD schemas using the xsd.exe tool mentioned earlier).
  1. public void ProcessData(object receivedData)
  2. {
  3.     StringReader sr = null;
  4.     try
  5.     {
  6.         string data = (string)receivedData;
  7.         sr = new StringReader(data);
  8.         //Get initial team data
  9.         if (_Teams == null &amp;&amp; data.Contains("Teams"))
  10.         {
  11.             XmlSerializer xs = new XmlSerializer(typeof(Teams));
  12.             _Teams = (Teams)xs.Deserialize(sr);
  13.             UpdateBoard();
  14.         }
  15.  
  16.         //Get updated score data
  17.         if (data.Contains("ScoreData"))
  18.         {
  19.             XmlSerializer xs = new XmlSerializer(typeof(ScoreData));
  20.             ScoreData scoreData = (ScoreData)xs.Deserialize(sr);
  21.             //ScoreDataHandler handler = new ScoreDataHandler(UpdateScoreData);
  22.             //this.Dispatcher.BeginInvoke(handler, new object[] { scoreData });
  23.             UpdateScoreData(scoreData);
  24.         }
  25.     }
  26.     catch { }
  27.     finally
  28.     {
  29.         if (sr != null) sr.Close();
  30.     }
  31. }
As team and score data is pushed from the server to the client it’s updated on the Silverlight interface as shown next: The complete code for the application including the WCF duplex polling service and the Silverlight client can be downloaded here. Twitter Already on Twitter and interested in getting live updates about blog posts and other information?  Subscribe to my Twitter feed at http://www.twitter.com/DanWahlin.

Pushing Data to a Silverlight Client with a WCF Duplex Service - Part I

Posted on June 16, 2008 by dwahlin.
Categories: C#, Contributors, Silverlight.
Silverlight provides several different ways to access data stored in remote locations.  Data can be pulled from Web Services and RESTful services and even pushed from servers down to clients using sockets (see my previous articles on sockets here, here and here).  Silverlight 2 Beta 2 introduces another way to push data from a server to a client using Windows Communication Foundation (WCF) and HTTP.  WCF's support for duplex service contracts makes this possible and opens up unique opportunities for pumping data to Silverlight clients.  In this first part of a two part series I'll demonstrate how a WCF push service can be created and cover the steps to get a sample service up and running.  The second article will focus on the client and show how to communicate with a WCF duplex service and listen for data that's sent. Many of the WCF services out there follow the simple request-response mechanism to exchange data which works well for many applications.  However, in addition to standard HTTP bindings, WCF also supports several others including a polling duplex binding made specifically for Silverlight which allows a service to push data down to a client as the data changes.  This type of binding isn't as "pure" as the push model available with sockets since the Silverlight client does poll the server to check for any queued messages, but it provides an efficient way to push data to a client without being restricted to a specific port range.  Once a communication channel is opened messages can be sent in either direction.  The Silverlight SDK states the following about how communication works between a Silverlight client and a duplex service: "The Silverlight client periodically polls the service on the network layer, and checks for any new messages that the service wants to send on the callback channel. The service queues all messages sent on the client callback channel and delivers them to the client when the client polls the service."

Creating Contracts

When creating a WCF duplex service for Silverlight, the server creates a standard interface with operations.  However, because the server must communicate with the client it also defines a client callback interface.  An example of defining a server interface named IGameStreamService that includes a single service operation is shown next:
  1. [ServiceContract(Namespace = "Silverlight", CallbackContract = typeof(IGameStreamClient))]
  2. public interface IGameStreamService
  3. {
  4. [OperationContract(IsOneWay = true)]
  5. void GetGameData(Message receivedMessage);
  6. }
This interface is a little different from the standard WCF interfaces you may have seen or created.  First, it includes a CallbackContract property that points to the client interface.  Second, the GetGameData() operation is defined as a one way operation.  Client calls are not immediately returned as a result of setting IsOneWay to true and are pushed to the client instead.  The IGameStreamClient interface assigned to the CallbackContract is shown next.  It allows a message to be sent back to the client by calling the ReceiveGameData() method.
  1. [ServiceContract]
  2. public interface IGameStreamClient
  3. {
  4. [OperationContract(IsOneWay = true)]
  5. void ReceiveGameData(Message returnMessage);
  6. }

Creating the Service

Once the server and client contracts are defined a service class can be created that implements the IGameStreamService interface.  The following code creates a service that simulates a basketball game (similar to the one I demonstrated for using Sockets with Silverlight) and sends game updates to a Silverlight client on a timed basis.
  1. using System;
  2. using System.ServiceModel;
  3. using System.ServiceModel.Channels;
  4. using System.Threading;
  5.  
  6. namespace WCFPushService
  7. {
  8.     public class GameStreamService : IGameStreamService
  9.     {
  10.         IGameStreamClient _Client;
  11.         Game _Game = null;
  12.         Timer _Timer = null;
  13.         Random _Random = new Random();
  14.  
  15.         public GameStreamService()
  16.         {
  17.             _Game = new Game();
  18.         }
  19.  
  20.         public void GetGameData(Message receivedMessage)
  21.         {
  22.  
  23.             //Get client callback channel
  24.             _Client = OperationContext.Current.GetCallbackChannel&lt;IGameStreamClient&gt;();
  25.  
  26.             SendData(_Game.GetTeamData());
  27.             //Start timer which when fired sends updated score information to client
  28.             _Timer = new Timer(new TimerCallback(_Timer_Elapsed), null, 5000, Timeout.Infinite);
  29.         }
  30.  
  31.         private void _Timer_Elapsed(object data)
  32.         {
  33.             SendData(_Game.GetScoreData());
  34.             int interval = _Random.Next(3000, 7000);
  35.             _Timer.Change(interval, Timeout.Infinite);
  36.         }
  37.  
  38.         private void SendData(object data)
  39.         {
  40.             Message gameDataMsg = Message.CreateMessage(
  41.                 MessageVersion.Soap11,
  42.                 "Silverlight/IGameStreamService/ReceiveGameData", data);
  43.  
  44.             //Send data to the client
  45.             _Client.ReceiveGameData(gameDataMsg);
  46.         }
  47.     }
  48. }
The service first creates an instance of a Game class in the constructor which handles simulating a basketball game and creating new data that can be sent to the client.  Once the client calls the service's GetGameData() operation (a one-way operation), access to the client's callback interface is retrieved by going through the OperationContext object and calling the GetCallbackChannel() method.  The teams involved in the game are then created on the server and pushed to the client by calling the SendData() method.  This method calls the Game object's GetTeamData() method.  Although not shown here (but included in the sample code), the GetTeamData() method generates an XML message and returns it as a string.  The SendData() method then creates a WCF Message object, defines that SOAP 1.1 will be used (required for this type of communication) and defines the proper action to be used to send the XML data to the client.  The client's ReceiveGameData() operation is then called and the message is ultimately sent to the client. Once the client receives the team data the server will start sending simulated score data on a random basis.  When the Timer object created in the initial call to GetGameData() fires the _Timer_Elapsed() method is called which gets updated score information and pushes it to the Silverlight client by calling the SendData() method.

Creating the Service Factory

Once the service class is created a service factory can be created along with a service host.  The factory is responsible for creating the appropriate host while the host defines the service endpoint.  An example of creating service factory and host classes is shown next:
  1. using System;
  2. using System.ServiceModel;
  3. using System.ServiceModel.Activation;
  4. using System.ServiceModel.Channels;
  5. using System.ServiceModel.Configuration;
  6.  
  7. namespace WCFPushService
  8. {
  9.     public class PollingDuplexServiceHostFactory : ServiceHostFactoryBase
  10.     {
  11.         public override ServiceHostBase CreateServiceHost(string constructorString,
  12.             Uri[] baseAddresses)
  13.         {
  14.             return new PollingDuplexServiceHost(baseAddresses);
  15.         }
  16.     }
  17.  
  18.     class PollingDuplexServiceHost : ServiceHost
  19.     {
  20.         public PollingDuplexServiceHost(params System.Uri[] addresses)
  21.         {
  22.             base.InitializeDescription(typeof(GameStreamService), new UriSchemeKeyedCollection(addresses));
  23.         }
  24.  
  25.         protected override void InitializeRuntime()
  26.         {
  27.             // Define the binding and set time-outs
  28.             PollingDuplexBindingElement bindingElement = new PollingDuplexBindingElement()
  29.             {
  30.                 PollTimeout = TimeSpan.FromSeconds(10),
  31.                 InactivityTimeout = TimeSpan.FromMinutes(1)
  32.             };
  33.  
  34.             // Add an endpoint for the given service contract
  35.             this.AddServiceEndpoint(
  36.                 typeof(IGameStreamService),
  37.                 new CustomBinding(
  38.                     bindingElement,
  39.                     new TextMessageEncodingBindingElement(
  40.                         MessageVersion.Soap11,
  41.                         System.Text.Encoding.UTF8),
  42.                     new HttpTransportBindingElement()),
  43.                     "");
  44.  
  45.             base.InitializeRuntime();
  46.         }
  47.     }
  48. }
This code was pulled directly from the Silverlight SDK example which provides a great starting point for creating WCF/Silverlight polling duplex services.  The service factory class (PollingDuplexServiceHostFactory) creates a new instance of the service host class (PollingDuplexServiceHost) within the CreateServiceHost() method.  The service host class then overrides the InitializeRuntime() method and creates a PollingDuplexBindingElement instance which defines the client's polling and inactivity timeouts.  The Silverlight SDK states the following about the PollingDuplexBindingElement class's PollTimeout and InactivityTimeout properties: "The PollTimeout property determines the length of time (in milliseconds) that the service holds a poll from the client before returning. The InactivityTimeout property determines the length of time (in milliseconds) that can elapse without any message exchange with the client before the service closes its session." The PollingDuplexBindingElement class is located in an assembly named System.ServiceModel.PollingDuplex.dll which is part of the Silverlight SDK.  You'll need to reference the assembly in your WCF project as well as the System.ServiceModel.Channels namespace to use the PollingDuplexBindingElement class.  Once the binding element is created a call is made to the host object's AddServiceEndPoint() method which references the PollingDuplexBindingElement object and the server's IGameStreamService interface to create a custom binding that uses HTTP under the covers for message exchange. Once the factory and service classes are created the factory can be referenced in the service's .svc file in the following manner:
  1. <%@ ServiceHost Language="C#" Factory="WCFPushService.PollingDuplexServiceHostFactory" %>
Looking through all of the code you can see that there's definitely some initial setup work required to get a Silverlight callable WCF duplex service created.  Since the client does have to poll the service to check for queued messages you may wonder what the benefit is over writing a manual polling Silverlight client that calls a WCF service.  Microsoft's Scott Guthrie was kind enough to provide additional details on that subject.  Here's what he had to say: "The duplex support does use polling in the background to implement notifications – although the way it does it is different than manual polling. It initiates a network request, and then the request is effectively “put to sleep” waiting for the server to respond (it doesn’t come back immediately). The server then keeps the connection open but not active until it has something to send back (or the connection times out after 90 seconds – at which point the duplex client will connect again and wait). This way you are avoiding hitting the server repeatedly – but still get an immediate response when there is data to send." When the client polls in the background it sends the following message to the server:
  1. &lt;s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"&gt;
  2.     &lt;s:Body&gt;
  3.         &lt;wsmc:MakeConnection xmlns:wsmc="http://docs.oasis-open.org/ws-rx/wsmc/200702"&gt;
  4.             &lt;wsmc:Address&gt;
  5.                 http://docs.oasis-open.org/ws-rx/wsmc/200702/anoynmous?id=7f64eefe-9328-4168-8175-1d4b82bef9c3
  6.             &lt;/wsmc:Address&gt;
  7.         &lt;/wsmc:MakeConnection&gt;
  8.     &lt;/s:Body&gt;
  9. &lt;/s:Envelope&gt;
In the next article I'll demonstrate how to call a WCF polling duplex service and listen for data in a Silverlight 2 application.  An example of the Silverlight interface that will be discussed is shown next: In the meantime, you can download the Silverlight 2 Beta 2 sample application including the WCF service and Silverlight client here. Interested in getting live updates about blog posts and other information?  Subscribe to my Twitter feed at http://www.twitter.com/DanWahlin.

Outsource Digital Labor at Task Market [Personal Outsourcing]Lifehacker

Posted on June 3, 2008 by Jason Fitzpatrick.
Categories: C#, Software.
Microsoft’s launched a tech-oriented outsourcing marketplace called Task Market in Tech Preview (that is, beta). If you need a logo for your company letterhead, but lack the Illustrator chops, or you have a knack for writing compelling resumes, Task Market’s worth checking out—outsource the first and advertise the second on the market. Jobs most suitable for Task Market cost between $0 and $500, and the product must be something that can be delivered in a digital format. Logo creation, web design, photo editing, proof reading, and document translation are just a few potential items. Get paid or pay your freelancer via PayPal, and rate their work after it’s complete. Looks like a good place to test-drive a side business freelancing. Have you ever outsourced work or freelanced using a Task Market-like open forum? Tell us your experience in the comments.
Task Market

Working with the GridView and the System.Data.Linq.Binary TypeDan Wahlin's WebLog

Posted on May 14, 2008 by dwahlin.
Categories: ASP.NET, C#, Contributors.

I'm working with a database table that has a RowVersion field defined as a TimeStamp data type.  The TimeStamp field is there to add concurrency into the application to ensure a row hasn't changed while a user is trying to update or delete it.  When the TimeStamp field value is queried and added into the LINQ to SQL generated object it adds it adds the data as a System.Data.Linq.Binary type as opposed to a byte array.

The GridView that is displaying records and allowing users to delete them defines the primary key in the DataKeyNames property as well as the RowVersion field so that the data is persisted across postback operations for each row.  That's important because without the RowVersion value I can't update or delete a record and still take advantage of the concurrency features built-in to LINQ to SQL.  The GridView definition looks like the following.  Notice that two fields are defined in the DataKeyNames property which is par for the course if you're working with TimeStamp fields or multiple keys:

  1. <span >&lt;<span >asp<span >:<span >GridView <span >ID<span >=&quot;gvApprovedData&quot; <span >runat<span >=&quot;server&quot; <span >BackColor<span >=&quot;White&quot;
  2.     <span >BorderColor<span >=&quot;#DEDFDE&quot; <span >BorderStyle<span >=&quot;None&quot; <span >BorderWidth<span >=&quot;1px&quot; <span >CellPadding<span >=&quot;6&quot;
  3.     <span >ForeColor<span >=&quot;Black&quot; <span >GridLines<span >=&quot;Vertical&quot; <span >Width<span >=&quot;50%&quot; <span >DataKeyNames<span >=&quot;PrimaryKeyField,RowVersion&quot;
  4.     <span >AutoGenerateColumns<span >=&quot;False&quot; <span >onrowcommand<span >=&quot;gvApprovedData_RowCommand&quot;&gt;
  5. <span ><br><span >    ....Columns....
  6. <span >&lt;/<span >asp<span >:<span >GridView<span >&gt;


When I tried to get the serialized TimeStamp data back into the RowVersion property of the LINQ to SQL object (which is the Binary type I mentioned earlier) I kept getting a conversion error initially.  I tried several different options such as the Convert class, converting character arrays to byte arrays, etc. but nothing worked at first.  The main problem was that I was trying to convert the data held in key.Values[1] object to a String type and then convert that back to the Binary type.  After playing around with it more I tried the super simple way of converting the data.  I cast the serialized value directly to the Binary type which was much easier than I was expecting (see the code below).  Very nice now that I know how it expects things to work!

  1. <span >protected void gvApprovedData_RowCommand(<span >object sender, <span >GridViewCommandEventArgs e)
  2. {
  3.     <span >int index = <span >int.Parse(e.CommandArgument.ToString());
  4.     <span >DataKey key = <span >this.gvApprovedData.DataKeys[index];           
  5.     <span >BusinessObject bo = <span >new <span >BusinessObject();
  6.     <span >CustomObject obj = <span >new <span >CustomObject { PrimaryKeyField = <span >new <span >Guid(key.Value.ToString()), RowVersion = (<span >Binary)key.Values[1]};
  7.     <span >OperationStatus opStatus = bo.DeleteRow(obj);
  8.     <span >if (opStatus.Status)
  9.     {
  10.         BindGrids();
  11.     }
  12.     <span >else
  13.     {
  14.         <span >this.lblError.Text = <span >&quot;&lt;br /&gt;An error occurred while trying to remove the row&quot;;
  15.     }
  16. }