Wintellect  

The following is a rapid-fire description of channels, where they come from, and a code sample to illustrate:

Channels are one of the more complex parts of a WCF application. For those that are new to WCF, a channel is a sink or a source of a message, and they are largely hidden from the purview of the application developer. In fact, it is entirely possible (and common) to write a fully functional WCF application and not know a thing about channels. Even though they are not easily visible at the ServiceModel layer, they are busy behind the scenes sending, receiving, or otherwise mangling messages.

All channels are not created equal. In the WCF type system, there are channels for each supported transport, security functionality, and messaging protocol. Furthermore, a channel has at least one shape. For a description of channel shapes, see Kenny Wolf's blog. Since messaging applications frequently need to send messages securely over a given transport with a given protocol or choreography, channels can be stacked. Each channel in the stack is responsible for a specific set of functionality in the application.

User code never directly instantiates a channel; that job is reserved for special factory objects in the WCF type system. These factory objects come in two flavors: Channel Listeners and Channel Factories. Channel listeners create receiving channels, and channel factories create sending channels. Channel listeners have the added pleasure of listening for incoming connections (think sockets). A given channel factory or channel listener can create more than one kind of channel, but they are typically grouped based on functionailty. For example, the WCF type system contains a channel listener for TCP/IP traffic, and another one for MSMQ traffic. Since channels reside in a stack, and channel listeners/factories create channels, channel listeners/factories are also stacked at runtime.

User code never directly instantiates a channel listener or channel factory; that job is reserved for a BindingElement. The WCF API contains several BindingElements, and each one represents some messaging functionality (e.g. transport, messaging protocols, security, transactional support, encoding). All BindingElements have a common base type, and that base type defines methods called BuildChannelFactory and BuildChannelListener. As their name implies, these methods build at least one channel factory or channel listener, respectively. Application code can instantiate and use BindingElement to build a single channel listener or channel factory. It is a one-stop shop for both the sender and the receiver.

In practice, however, BindingElements are most frequently created by a Binding. A Binding’s primary job is to create a collection of BindingElements, and use that collection of BindingElements to build either a stack of channel factories or a stack of channel listeners. All Bindings have a common base type, and that base type defines a method named CreateBindingElements. At runtime, either the sending application or the receiving application calls this method, and then uses the returned BindingElementCollection to create a stack of channel listeners or channel factories.

Channel listeners, channel factories, and channels all have a common state machine. Since these objects are typically arranged in a stack, the entire stack must transition through the state machine in harmony.

To summarize:

  1. Binding begat a BindingElementCollection
  2. BindingElementCollection begat a stack of channel listeners or channel factories
  3. RECEIVER: stack of channel listeners begat a stack of channels
  4. SENDER: stack of channel factories begat a stack of channels

Trying to keep this straight can be challenging at first. If you add the state transitions, and the fact that a channel listener or factory stack can create multiple channel stacks, it can be quite confusing at first. In the end, however, this model provides tremendous extensibility and functionality, so I think it is a good one.

One great way to learn channels and the impact ServiceModel code has on them is to write a custom channel, plug it into a running application, and watch what is going on. The following code sample does just that: DelegatorChannelDemo1.zip (140.11 KB)

The zip file contains two projects: TestApp and DelegatorChannel. DelegatorChannel project contains a channel factory, a channel listener, a BindingElement, and a Binding that will place a custom channel in the channel stack at runtime. These channels simply dump text to the console for all state changes, as well as all method calls. The channel factory and channel listener do the same. The Binding in the DelegatorChannel project inserts a custom BindingElement in the BindingElementCollection for the BasicHttpBinding, NetTcpBinding, WsHttpBinding, and NetMsmqBinding. The TestApp project flexes this binding in several different MEPS (Datagram, Request/Reply, and Duplex).

BTW - My book should be on the bookshelves by TechEd (yay).

It has been a while since I have blogged - my apologies. Life has been hectic.

One of the "not so fun" parts of writing a book on a beta technology like WCF is the constant movement of the API (not to mention changing the ship vehicle).

One change in the June CTP (appears to persist in the July CTP as well) that caught my attention is the change to the WS-MEX default behavior. In the old days (a few months ago) you could add an address to ServiceHost's constructor, and a WS-Mex endpoint would automagically appear. No mas. As of the June CTP, WS-Mex is off by default. There is quite a bit of documentation regarding how to enable WS-Mex in config files, but I could find none about how to do it imperatively. I think config files are great, but I like the ability to program too. After some time in the debugger and in reflector, it appears to be possible, but not pretty.

To configure a ServiceHost to open a WS-Mex endpoint in a simple WCF receiving app, do the following:

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;

// implement the IHelloWCF interface
sealed class Receiver : IHelloWCF {
  static void Main(){

    // define the base address to listen on
    Uri baseAddress = new Uri("
http://localhost:5000/HelloWCF");

    // create the Binding
    BasicHttpBinding binding = new BasicHttpBinding();

    // new-up a ServiceHost type in a using statement
    using(ServiceHost svc = new ServiceHost(typeof(Receiver), baseAddress)){

      // use the contract, binding, and address to configure main endpoint
      svc.AddServiceEndpoint(typeof(IHelloWCF), binding, String.Empty);

      // add the Service Metadata behavior **NEW**
      ServiceMetadataBehavior mexBehavior = new ServiceMetadataBehavior();
      svc.Description.Behaviors.Add(mexBehavior);

      // add the endpoint for metadata requests **NEW**
      Binding mexBinding = MetadataExchangeBindings.CreateMexHttpBinding();
      svc.AddServiceEndpoint(typeof(IMetadataExchange), mexBinding, "mex");

      // begin listening on all endpoints
      svc.Open();

      Console.WriteLine("the receiver is ready");
      Console.ReadLine();
    }
  }

  // implement the method defined in the service contract
  public void Say(String input){
    Console.WriteLine("Message received, the body contains: {0}", input);
  }
}

// define the service contract
[ServiceContract]
interface IHelloWCF {
  [OperationContract]
  void Say(String input);
}

The new stuff has **NEW** in the comments. Basically, you now have to add a Mex endpoint manually. There are a few catches though. First, you have to call the MetadataExchangeBindings.CreateMexHttpBinding method to get the correct mex binding. It is worth noting that this is the only binding that defines factory methods. Also, you have to add the ServiceMetadataBehavior to the description BEFORE you add the mex endpoint.

What we have come to know and love as WinFx is now called the .NET Framework 3.0 (see http://www.eweek.com/article2/0,1895,1974865,00.asp).

It doesn' t look like this is anything more than a branding stunt, but I now have to go back and change parts of my book :)

Last week I presented an MSDN webcast titled "The Lifetime of a WCF Message". As promised, the demo code shown is here: LifeOfAMessage.zip ( KB)

A couple of things to remember about the source:

  1. It was built with the WinFx Feb CTP, but should upgrade to Beta 2 with no problem :)
  2. Demos 1 and 2: set WCFReceiver101 and WCFSender101 as the startup projects
  3. Demo 3: run the BindingElements project, then the MessageEncodings project
  4. Demo 4: Set PerfTestSender and PerfTestReceiver as the startup project

WCF is all about sending and receiving messages. There are many settings that have an impact on how a WCF application will scale. The following describes how the settings for instancing modes and concurrency mode impact the scalability of a WCF receiving application, and when they make thread synchronization necessary in your code.

Instancing Background Info

When a receiving application receives a message, that message gets dispatched to an object’s instance method. The lifetime of this receiving object can be tied to one or more received messages. The WCF programming model allows developers and administrators to change this association through the InstanceContextMode instance property on the ServiceBehaviorAttribute type. The possible settings are:

Single: every received message is dispatched to the same object (a singleton)

PerCall (default): every received message is dispatched to a newly created object

PerSession: messages received within a session (usually a single sender) are dispatched to the same object

Shareable: messages received within a session (can be one or more senders) are dispatched to the same object

The following is a service contract and receiving type definition that sets the InstanceContextMode to Single:

[ServiceContract]

public interface ISomeContract

{

  [OperationContract(IsOneWay=true)]

  void SomeOperation(Int32 number);

}

 

[ServiceBehavior(

  InstanceContextMode=InstanceContextMode.Single)]

sealed class Receiver : ISomeContract {

 

  internal Receiver() {

    Console.WriteLine("the receiver has been created\n");

  }

 

  public void SomeOperation(Int32 number) {

    // Do work here

  }

}

As you may have guessed, this setting has a direct impact on the lifetime of the receiving object, and it impacts the way we can share receiver object state when processing messages.

Concurrency Background

Since WCF is an asynchronous messaging platform. It makes extensive use of asynchronous I/O, and as a result, each received message may be dispatched to a receiving object by different threads. This feature allows WCF to use the CPU efficiently, and as a result, allows WCF applications to scale. The WCF programming model allows developers and administrators to choose how threads are utilized when messages are dispatched through the ConcurrencyMode instance property on the ServiceBehaviorAttribute type. The possible settings are:

Single (default): only one thread may access the receiver object at a time

Multiple: multiple threads may access the receiver object concurrently

Reentrant: only one thread may access the receiver object at a time, but callbacks may re-enter that object on another thread (Useful when performing asynchronous I/O)

The following is a service contract and receiving type definition that sets the ConcurrencyMode to Multiple.

[ServiceContract]

public interface ISomeContract

{

  [OperationContract(IsOneWay=true)]

  void SomeOperation(Int32 number);

}

 

[ServiceBehavior(

  InstanceContextMode=InstanceContextMode.Single,

  ConcurrencyMode=ConcurrencyMode.Multiple)]

sealed class Receiver : ISomeContract {

 

  internal Receiver() {

    Console.WriteLine("the receiver has been created\n");

  }

 

  public void SomeOperation(Int32 number) {

    // Do work here (must consider multiple threads)

  }

}

When is synchronization necessary?

Both the InstanceContextMode and the ConcurrencyMode instance properties on the ServiceBehaviorAttribute type play a role in determining whether or not it is necessary to synchronize access to a receiver’s state.

Let’s first consider the default settings of InstanceContextMode=InstanceContextMode.PerCall and ConcurrencyMode=Single. These settings dictate that a new receiver object will be created for every received message that is properly formatted, and that a single thread will invoke the instance method on the receiver object. The following service contract and receiver type definition can be used to test how these settings influence message processing (Sender code omitted for clarity):

[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall,

                 ConcurrencyMode=ConcurrencyMode.Single)]

sealed class Receiver : ISomeContract {

  // member variable for race condition

  Int32 someNumber;

 

  internal Receiver() {

    Console.WriteLine("a receiver has been created");

  }

 

  static void Main(string[] args){

    // create the address and binding

    Uri address = new Uri("net.tcp://localhost:4000/ISomeContract");

    NetTcpBinding binding = new NetTcpBinding(SecurityMode.None, false);

 

    // create the service host and add an endpoint

    Console.WriteLine("Creating ServiceHost");

    ServiceHost svc = new ServiceHost(typeof(Receiver));

    svc.AddServiceEndpoint(typeof(ISomeContract), binding, address);

 

    // show the concurrency mode

    ServiceBehaviorAttribute annotation = svc.Description.Behaviors.Find<ServiceBehaviorAttribute>();

    Console.WriteLine("important behaviors:");

    Console.WriteLine("\tconcurrency mode = {0}", annotation.ConcurrencyMode);

    Console.WriteLine("\tinstance context mode = {0}", annotation.InstanceContextMode);

    // open the service host (Start listening, among other things)

    Console.WriteLine("opening ServiceHost");

    svc.Open();

    Console.WriteLine("the Receiver is ready\n");

 

    // wait before exiting process

    Console.ReadLine();

 

  }

 

  // method can only be used with Concurrency Mode = PerCall

  public void SomeOperation(Int32 number) {

    // set the field value to the parameter and wait

    someNumber = number;

 

    Random rand = new Random();

    Thread.Sleep(rand.Next(1000));

    // show the current value of the field and parameter

    // with percall, they will always be the same

    Console.WriteLine("parameter = {0}, somenumber = {1}, thread = {2}\n",

      number.ToString(),

      someNumber.ToString(),

      Thread.CurrentThread.ManagedThreadId);

  }

}

If a sending application sends 5 messages to this receiving application, the SomeOperation method is invoked 5 times synchronously by the same thread. The following is the console output:

 

Since one and only one thread can interact with the receiver object at a time, and each message is dispatched to a new receiver object, there is no need write thread synchronization code in our receiver type definition.

If we change the InstanceContextMode to Single, we see the following output:

Here we have a single instance of the receiver type, but since the ConcurrencyMode is still Single, there is no need to write thread synchronization code in the SomeOperation method.

If, however, we change the ConcurrencyMode to Multiple, we see the following:

Clearly, we now have a race condition, and as a result, we have to write synchronization code in our SomeOperation method. While this can be quite a chore, allows us to service received messages more efficiently than if we allow only one thread at a time to work with the receiver object.

Repeating this process for the different settings of InstanceContextMode and ConcurrencyMode, the following grid becomes apparent (the non-shaded cells indicate whether or not synchronization code is necessary):

InstanceContextMode

ConcurrencyMode

Single (Default)

Multiple

Reentrant

Single

No

Yes

Yes

Shareable

No

Yes

Yes

PerSession

No

Yes

Yes

PerCall (Default)

No

No

No

Some thoughts on the table above…

1) Reentrant seems goofy. I don't see the compelling reason to use it (it is like single, but callbacks must be synchronized).

2) Single seems like a huge scalability limiter, and I don't think it should be used.

3) ConcurrencyMode should be set to Multiple. In my view, if a receiving application is going to scale, it must set concurrency mode to Multiple. If single or Reentrant are used, messages stack up as they wait to be processed, and that is badness.

I spoke briefly at Devscovery NYC tonight about WCF and WS-ReliableMessaging. As promised, the code is here:

 
Read the readme.txt file in the archive before running the sample.
 
Some other things you can do with this sample:
1) Add IsInitiating and/or IsTerminating to the SubmitOrder OperationContract
2) Create a new channel stack in the loop on the Sender.
 
When I have a bit more time (in the next week or so) I will expand on what these settings do...
One of the cooler things about WCF shown at PDC last year was the use of WCF's custom XML stack. In a nutshell, WCF wraps the functionality of existing System.Xml types to allow greater messaging functionality. The types in WCF's xml stack are defined in the System.Runtime.Serialization assembly. Some interesting types in this assembly are System.Xml.XmlDictionary, System.Xml.XmlDictionaryReader, and System.Xml.XmlDictionaryWriter. This post extends part of Doug Purdy's COM326 PDC talk.
 
Consider the following XML content:
<?xml version="1.0" encoding="utf-8"?><Company>Wintellect</Company>
 
Using pre-WCF types we write/read this content to/from a stream using the following code:
 
    // write content to stream using XmlWriter
    MemoryStream stream = new MemoryStream();
    using (XmlWriter writer = XmlWriter.Create(stream))
    {
      writer.WriteElementString("Company", "Wintellect");
      writer.Flush();
      // shows 70 bytes written
      Console.WriteLine("XmlWriter wrote {0} bytes", stream.Position);
      stream.Position = 0;
      Console.WriteLine("data read from stream:\n{0}\n", new StreamReader(stream).ReadToEnd());
    }
 
Writing roughly the equivalent code using the XML Stack in WCF is as follows:
 
    // write content to stream using the text flavor of WCF's XmlDictionaryWriter
    stream = new MemoryStream();
    using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(stream, Encoding.UTF8, false))
    {
      writer.WriteStartDocument();
      writer.WriteElementString("Company", "Wintellect");
      writer.Flush();
      // shows 67 bytes written
      Console.WriteLine("XmlDictionaryWriter (Text-UTF8) wrote {0} bytes", stream.Position);
      stream.Position = 0;
      Console.WriteLine("data read from stream:\n{0}\n", new StreamReader(stream).ReadToEnd());
    }
 
From a messaging perspective, what if we wanted to create MTOM encoded XML? Well, we can do the following:
 
    // write content to stream using the MTOM flavor of WCF's XmlDictionaryWriter
    stream = new MemoryStream();
    using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateMtomWriter(stream, Encoding.UTF8, Int32.MaxValue, "Application/soap+xml"))
    {
      writer.WriteStartDocument();
      writer.WriteElementString("Company", "Wintellect");
      writer.Flush();
      // show that 546 bytes were written
      Console.WriteLine("XmlDictionaryWriter (MTOM-UTF8) wrote {0} bytes", stream.Position);
      stream.Position = 0;
      Console.WriteLine("data read from stream:\n{0}\n", new StreamReader(stream).ReadToEnd());
    }

One of the takeways from the previous example is that MTOM is not always optimal! It is important to remember that MTOM is intended for transporting binary data and allowing signatures to be safely applied to that data (But I digress).
 
You may have seen that WCF fully supports the XmlInfoset. Nowhere is this more apparent than when writing binary XML. Keep in mind that binary XML is still XML, it is just encoded differently. You can write binary XML with the WCF XML stack like the following:
 
    // write content to stream using the binary flavor of WCF's XmlDictionaryWriter
    // without using a dictionary
    stream = new MemoryStream();
    using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(stream, null, null))
    {
      writer.WriteStartDocument(); // does nothing in Feb CTP
      writer.WriteElementString("Company", "Wintellect");
      writer.Flush();
      // shows that 21 bytes were written
      Console.WriteLine("XmlDictionaryWriter (Binary, no dictionary) wrote {0} bytes", stream.Position);
      stream.Position = 0;
      XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(stream);
      reader.Read();
      Console.WriteLine("data read from stream:\n{0}\n", reader.ReadOuterXml());
    }
 
Now to the dictionary part of the XmlDictionaryWriter / XmlDictionaryReader. The WCF XML stack allows XML data to be substitued with other data. In practical terms, this allows you to substitue XML content and "compress" the resultant data. The following code snippet shows how:
 
    // write content to stream using the binary flavor of WCF's XmlDictionaryWriter
    // with a custom dictionary
    stream = new MemoryStream();
    XmlDictionary dictionary = new XmlDictionary();
    XmlDictionaryString entry = dictionary.Add("Company");
 
    using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(stream, dictionary, null))
    {
      writer.WriteStartDocument(); // does nothing in FebCTP
      writer.WriteElementString(entry, XmlDictionaryString.Empty, "Wintellect");
      writer.Flush();
   // shows 14 bytes written
      Console.WriteLine("XmlDictionaryWriter (Binary w/dictionary) wrote {0} bytes", stream.Position);
      stream.Position = 0;
      XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(stream, dictionary);
      reader.Read();
      Console.WriteLine("data read from stream:\n{0}\n", reader.ReadOuterXml());
    }
 
In my view, this is way cool. The Project is available here:
 
Dictionaries.zip (14.26 KB)  (NOTE: This sample requires the FebCTP of WCF....)
 
And will produce output like the following:
 

As anyone who has written a WCF application knows, getting a "Hello World" app to run takes a bit more effort than doing the equivalent in Windows Forms. Don't get me wrong, it is pretty straightforward and simple after you get the hang of it, but it does take a few minutes of effort. The attached VS Template is a way to streamline that process a little bit more.

The template creates contract, receiver, and sender projects and sets all the references properly (for the Feb CTP).

To install the template, download the zip file and place it in your My Documents\Visual Studio 2005\Templates\ProjectTemplates folder.

You can download the template here: WCF Solution.zip (28.6 KB)

When installed, the Solution appears as follows:

            

As some of you know, I began working on a WCF book several months ago. Currently I am looking to increase the size of my “Review Crew” (John Robbin’s term). Hopefully I am not opening myself up to hoards of email, but if you are interested in reviewing my book see the last section of this post. My hope is that more viewpoints will ensure the book:

1) addresses the topics developers must know,
2) properly addresses the topics developers are most interested in, and
3) explains WCF at the proper level of detail.

In general, this book is targeted at an advanced audience, and describes WCF internals from the inside-out. I expect to have the book on bookshelves by the Vista launch.

About the book

WCF is fundamentally a service-oriented XML messaging platform. The WCF team has successfully abstracted the XML messaging infrastructure away from the object model developers are most likely to use. Given this fact, three approaches are possible when explaining this technology:

1) Focus strictly on the Object Model (since this is where developers will most likely spend all of their time)
2) Focus strictly on WCF internals and the theory behind WCF
3) Blend the previous two approaches

This book takes the third approach, and I have taken some flack over it. Many believe that #1 is the best approach. Their belief stems from the assumption that the level of abstraction in the WCF platform releases developers from having to consider WCF internals or service-orientation in general.

My counterpoint is pretty straightforward. While it is true that WCF does not force developers to directly deal with the messy business of angle brackets and WS-* protocols, it does not completely release the developer from the responsibility making the mental shift to service-orientation. In much the same way that successful adoption of an object-oriented language like C++ or Java required developers to shift their thinking from procedural programming to object-orientation, successful adoption of WCF requires developers to evolve from a component-oriented mindset to a service-oriented mindset. If we fail to make this shift, we run the risk of missing out on many of the features offered through service orientation.

Even if we do not care about the features service-orientation offers, we should understand WCF infrastructure. In essence, we should know our platform. The CLR offers supporting evidence for this stance. The CLR team did a great job abstracting the Garbage Collector and the JIT Compiler away from the developer. As a result, it is technically possible for us to write .NET applications with little or no knowledge of how these subsystems work. Failing to understand these concepts, however, increases the risk that we will write inefficient applications. For example, a C++ developer moving to C# without any knowledge of the garbage collector will instinctively add a finalizer to all type declarations. Unknowingly, this developer will have increased the time required to allocate these objects and increased the lifetime of these objects. Technically this is not a bug, but it is certainly an inefficiency that could have been averted with a couple of hours spent in a book or a presentation on the topic.

In a similar vein, understanding WCF infrastructure can avert unnecessary inefficiencies in WCF applications, and allows developers to better leverage the functionality available in WCF. For example, changing the reliable session parameter in the constructor of a binding has a dramatic impact on the messaging choreography between endpoints. The WCF team has rightfully abstracted this choreography away from the developer and partially exposed it via compatible bindings. From the perspective of the developer, this messaging choreography is sometimes necessary, and sometimes it is not. It is only through an understanding of this choreography that a developer can make the decision whether or not to use this feature (not to mention what it would take to debug the interaction!). Indirectly, understanding the reliable messaging choreography requires a grasp of service orientation.

This book aims to achieve the right mix of service-orientation concepts and a deep exploration of the WCF programming model, thereby equipping the reader with the knowledge necessary to design, build, maintain, and version WCF applications.

If you disagree with my viewpoint

Feel free to send me an email (justins care of this company) and let me know your approach and why it’s better.

If you would like to be a member of the Review Crew

In general, I am looking for experienced .NET developers and architects that have full lifecycle experience with distributed applications. I am also open to hearing from folks who are experienced with WebSphere, BEA, etc. If you are interested, send me an email at (justins care of this company) that contains the following:

1) What is your experience with .NET
2) What is your experience with distributed applications
3) Are you a professional developer / architect? If so, what company(s) do you work for?

You might be asking yourself, “What’s in it for me?”
1) You will get to read the book before anyone else
2) You will have the satisfaction of a job well-done, and acknowledgement in the book
3) A free dinner next time I am in your area (or next time you are in Atlanta)
4) A signed copy of the book (the signature might actually reduce the value of the book ).

You might also be asking yourself, “What would I be signing up for?”
1) Checking technical accuracy of the book
2) Giving me feedback on how what you think
3) Letting me know what questions you have about the technology
4) Telling me what you would like to see added / removed from the book
5) Reviewing chapters in a timely manner
6) Agreeing in principle to an NDA

I will be accepting new members to the review crew over the next two weeks, so the deadline for submission is April 7.

I look forward to hearing from you!


 

I just moved a WPF / WCF application from my laptop to my workstation, and it suddenly started crashing Visual Studio as soon as the project loaded (those darn CTPs). After some hunting and pecking around, I came across this post:

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=234330&SiteID=1&PageID=2

It seems that WPF (at least the Feb CTP) will not work on multi-processor machines. I am sure this will be fixed soon, but in the meantime, you have to start VS, then force Visual Studio to use one processor...

One interesting feature of ClickOnce deployments is the capability to dynamically download files. These files can be anything: assemblies, images, help files, etc. This feature makes sense when you are trying to speed up installation time, or your application requires files that are used occasionally.

When compared to the default ClickOnce scenario, taking advantage of  this functionality requires two additional steps:

  1. changing the application manifest to include one or more optional file groups
  2. using the System.Deployment types to programmatically download the files in these optional file groups
When I searched on how to do this, all of the code samples I found used this feature for downloading everything except for assemblies. In my application I wanted to use this feature to download an assembly. My assumption was that I could just add the assemblies to a file group and all would be right. Well, that isn't the way it works out. Let me illustrate with an example.
 
Let's say I am writing a Notepad variant called  SecureMyNotepad, and I want to offer email functionality in my version of SecureMyNotepad. Let's also say that I want to split the email functionality into a separate assembly. We now have two assemblies - SecureMyNotepad.exe and WintellectMail.dll. Let's also assume that I want WintellectMail.dll to download only when the menu item "Email" is selected (see below)
 
 
The first thing I need to do is setup my applicatoin manifest. To do this, I go to the Publish tab in the Properties of my VS project and select "Application Files"
 
 
Notice that the Download Group is changed to "Mail". Internally Visual Studio uses this information to create the following manifest snippet:
 
<dependency optional="true">
  <dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="WintellectMail.dll"  size="20480" group="Mail">
    <assemblyIdentity name="WintellectMail" version="1.0.0.0" publicKeyToken="EF7FE5810D23B378" language="neutral" processorArchitecture="msil" />
    <hash>
      <dsig:Transforms>
        <dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
      </dsig:Transforms>
      <dsig:DigestMethod Algorithm="
http://www.w3.org/2000/09/xmldsig#sha1" />
      <dsig:DigestValue>g3tJEPdbE6y27FVgz/JrlF9Y1Ks=</dsig:DigestValue>
    </hash>
  </dependentAssembly>
</dependency>
 
Now when we publish the application and install it via the normal ClickOnce process the WintellectMail.dll assembly is not downloaded with SecureMyNotepad.exe. We have to write some code in the menu item event handler to download the files in the Mail file group. That code looks like the following:
 
    private void emailToolStripMenuItem_Click(object sender, EventArgs e)
    {
      // ClickOnce: Check to see if this app was deployed via ClickOnce
      // throw exception if it wasn't

      if (ApplicationDeployment.IsNetworkDeployed)
      {
        // ClickOnce: Get the current deployment
        deployment = ApplicationDeployment.CurrentDeployment;
 
        // ClickOnce: Check if the Mail FileGroup has been downloaded previously
        if (!deployment.IsFileGroupDownloaded("Mail"))
        {
          // if not, get it
          deployment.DownloadFileGroup("Mail");
        }
      }
      else
      {
        throw new InvalidProgramException("this application was not deployed via ClickOnce.");
      }
      // ClickOnce: Call method defined in WintellectMail.dll
      // Bad Code!
      WintellectMail.SendMail();
    }
 
The important point here is the SendMail call (last line of code). The type WintellectMail is defined in the newly downloaded WintellectMail.dll.
 
At runtime, this code throws an AssemblyLoadException. My first reaction was that I must not be downloading the assembly. After some thinking and some checking, I realized that indeed I wasn't, but the reason has nothing to do with the System.Deployment types.
 
Remember the JIT Compiler! When this method is invoked for the first time, the JIT Compiler goes to work. Among other things, the JIT Compiler triggers the assembly loader. The assembly loader is trying to load the WintellectMail assembly before the first instruction has been executed, hence the exception.
 
To fix our bad code, all we have to do is refactor our call to Wintellect.SendMail() into a local method. The JIT Compiler will not complain. The new code is below:
 
    private void emailToolStripMenuItem_Click(object sender, EventArgs e)
    {
      // ClickOnce: Check to see if this app was deployed via ClickOnce
      // throw exception if it wasn't

      if (ApplicationDeployment.IsNetworkDeployed)
      {
        // ClickOnce: Get the current deployment
        deployment = ApplicationDeployment.CurrentDeployment;
 
        // ClickOnce: Check if the Mail FileGroup has been downloaded previously
        if (!deployment.IsFileGroupDownloaded("Mail"))
        {
          // if not, get it
          deployment.DownloadFileGroup("Mail");
        }
      }
      else
      {
        throw new InvalidProgramException("this application was not deployed via ClickOnce.");
      }
      // ClickOnce: Call SendMail method
      SendMail();
    }
 
    // prevent inlining for all builds (good catch Daniel!)
    [MethodImpl(MethodImplOptions.NoInlining)]
    private void SendMail()
    {
      // ClickOnce: Call method defined in WintellectMail.dll
      WintellectMail.SendMail();
    }
 
As I said, this isn't exactly groundbreaking, but hopefully it saves someone some time...
 

Over the past year, I have become an avid viewer of the awful drama series Lost (awful because they show re-runs during the season). In honor of last night’s new episodes, I have written a distributed system that I like to call Lost Chat. It is reminiscent of the chat between Michael and “Walt”…

Lost Chat is comprised of two WCF (the technology formerly known as Indigo) console applications and one contract assembly. These components can be used in a traditional “chatting” scenario (hence the name). From a technical perspective, these components may be interesting since they use duplex communication, contain no configuration files, and interact directly with the Message type. While it may not always be feasible to use the Message type and a purely imperative coding model in production, I have found them to be extremely helpful in understanding WCF architecture. The VS solution containing the code will be available soon, and please forgive the formatting (or lack therof).

Let’s start with the contract. For simplicity, the contract is contained in a separate project and referenced by other Lost Chat components. The contract is simple:

 

// file: Contracts.cs

 

using System;

using System.ServiceModel;

 

// define the contract for the service

[ServiceContract(

    Namespace = "http://wintellect.com/LostChat",

    CallbackContract=typeof(IChatCallback),

    Session=false)]

public interface IChat

{

    [OperationContract(

        Action="urn:ServerChat",

        IsOneWay=true )]

    void SendChat(Message msg);

 

}

 

// define the contract for the callback

public interface IChatCallback

{

    [OperationContract(

        Action="urn:ServerChatCallback",

        IsOneWay=true)]

    void SendCallbackChat(Message msg);

}

Next, let’s build the receiver service (the entity that receives a message in Simplex communication). Remember that we are using the duplex message exchange pattern, so the hard-coded name “receiver” only has context in the first message exchange. Our receiver service has the following implementation:

 

// file: Receiver.cs

 

using System;

using System.Xml;

using System.Text;

using System.ServiceModel;

using System.Diagnostics;

 

class Service {

  public static IChatCallback Callback = null;

 

  static void Main() {

    // define the binding for the service

    WSDualHttpBinding binding =

        new WSDualHttpBinding(WSDualHttpSecurityMode.None);

    // use the Text encoder

    binding.MessageEncoding = WSMessageEncoding.Text;

   

    // define the address for the service

    Uri addressURI = new Uri(@"http://localhost:8000/Chat");

 

    // instantiate a Service host using the MyService type

    using (ServiceHost svc = new ServiceHost(typeof(MyService)))

    {

      // add an endpoint to the service with the address,

      // contract, and binding

      svc.AddServiceEndpoint(typeof(IChat), binding, addressURI);

          

      // open the service to start listening

      svc.Open();

      Console.WriteLine("LOST chat");

      Console.WriteLine("The service is ready");

      Console.WriteLine("4 8 15 16 23 42 to exit");

      Console.Write("You:> ");

      String cmdLine = null;

      while ((cmdLine = Console.ReadLine()) != "4 8 15 16 23 42"){

        if (Callback != null) {

          Callback.SendCallbackChat(GenerateMessage(cmdLine, "urn:ServerChatCallback"));

        }

        else{

          Console.WriteLine("You must wait to be contacted first");

        }       

        Console.Write("You:> ");

      }

    }

  }

 

  static Message GenerateMessage(String chatMessage, String action) {

    XmlDocument doc = new XmlDocument();

   

    // build the XML string

    StringBuilder xmlText = new StringBuilder();

    xmlText.Append("");

    xmlText.Append(chatMessage);

    xmlText.Append("");

 

    doc.LoadXml(xmlText.ToString());

    XmlNodeReader content = new XmlNodeReader(doc.DocumentElement);

 

    return Message.CreateMessage(action, content);

 }

}

 

// implement the service contract

[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]

sealed class MyService : IChat {

  public MyService() {

    // get the callback channel

    // interesting sessions / InstanceContextMode behavior

    // will only work for one sender (OK for Lost theme)