Building a Custom File Transport, Part 2: Server

For the server, I took the example code I posted a few weeks ago and started making modifications. I've replaced the binding with a new one for the File Transport (we'll cover that code later this week) and added some reasonable timeouts for all of the operations. I also added some debug messages for tracing if you want to play with this once the series is over and experiment.

The action of the server is a very simple one for demonstration. The server will take a message with action equal to "reflect" and reverse the contents of the message body. This reply gets sent back in a message with action equal to "reflection". Why http in the action? Just to show that actions are simply a description of how the message should be processed and don't have any inherent meaning until you give them one.

 using System;
using System.ServiceModel.Channels;
using FileTransport;

namespace FileReplyChannelServer
{
   class FileReplyChannelServer
   {
      static void Main(string[] args)
      {
         Console.Write("Creating listener...");
         Binding binding = new FileTransportBinding();
         Uri uri = new Uri("my.file://localhost/x");
         IChannelListener<IReplyChannel> listener = binding.BuildChannelListener<IReplyChannel>(uri, new BindingParameterCollection());
         listener.Open(TimeSpan.FromSeconds(5));
         Console.WriteLine(" done.");
         Console.Write("Creating channel...");
         IReplyChannel channel = listener.AcceptChannel(TimeSpan.FromSeconds(5));
         channel.Open(TimeSpan.FromSeconds(5));
         Console.WriteLine(" done.");
         Console.Write("Waiting for request...");
         while (channel.WaitForRequest(TimeSpan.FromMinutes(1)))
         {
            using (IRequestContext context = channel.ReceiveRequest(TimeSpan.FromSeconds(5)))
            {
               Console.WriteLine(" done.");
               using (Message message = context.RequestMessage)
               {
                  Console.WriteLine("Processing request: {0}", message.Headers.Action);
                  if (message.Headers.Action == "reflect")
                  {
                     string response = ProcessReflectRequest(message.GetBody<string>());
                     Console.Write("Sending reply...");
                     Message replyMessage = Message.CreateMessage(MessageVersion.Default, "reflection", response);
                     context.Reply(replyMessage, TimeSpan.FromSeconds(5));
                     Console.WriteLine(" done.");
                  }
               }
            }
            Console.Write("Waiting for request...");
         }
         Console.WriteLine(" terminated.");
         channel.Close(TimeSpan.FromSeconds(5));
      }

      static string ProcessReflectRequest(string request)
      {
         char[] output = new char[request.Length];
         for (int index = 0; index < request.Length; index++)
         {
            output[index] = request[request.Length - index - 1];
         }
         return new string(output);
      }
   }
}

This code works with the recent February CTP bits. If you don't have a WCF project template set up, you'll need to add references to the System.ServiceModel and System.Runtime.Serialization dlls. In Visual Studio, use Add Reference on the project to do this.

Next time: Building a Custom File Transport, Part 3: Client