Programming, Policitcs, and uhhh Pineapples.
 Monday, June 22, 2009

Where (Most?) Zombie Movies Go Wrong

6/22/2009 9:14:45 AM (Eastern Daylight Time, UTC-04:00)

As I was watching Diary of the Dead last night (I don't know why...I just have this thing for zombie movies), about half ways through the movie, it suddenly dawned upon me that none of the characters had uttered the word "zombie".  While the movie had many failings - the standard "Stupid Things People Do in Horror Movies" scenarios and taking itself too seriously - I felt that this was the most glaring one.  It's as if none of the characters had ever watched a zombie movie and didn't know the standard operating procedures with regards to zombie movies.

 Friday, June 19, 2009

I Learned A New Vocabulary Word Today...

6/19/2009 11:32:47 AM (Eastern Daylight Time, UTC-04:00)

Apophallation.

Apophallation is a technique resorted to by some species of air-breathing land slugs such as Limax maximus and Ariolimax spp. In these species of hermaphroditic terrestrial gastropod mollusks, after mating, if the slugs cannot successfully separate, a deliberate amputating of the penis takes place.

The slugs are hermaphroditic and have a full set of organs of both sexes. They have relatively large penises which, during mating, wrap around each other in a tight spiral. They sometimes have difficulty separating afterwards. When separating seems impossible, one slug gnaws off either its own, or its partner's penis, so that separation is then possible. No replacement penis grows, and the apophallated slug adopts a purely female function from that point onward.

:-O

(We've been having a pretty heavy slug infestation due to the inordinate amount of rainfall we've been getting...luckily, they don't seem to like pineapple)

As if that wasn't fascinating enough, their sex organs protrude from the side of their head.

And if that didn't boggle your mind, how about eating slugs (warning: cute and gag inducing at the same time)?

Youtube.

 Thursday, June 11, 2009

Discovering System.Linq.Expressions

6/11/2009 11:24:08 PM (Eastern Daylight Time, UTC-04:00)

I'm officially a fan: System.Linq.Expressions is one of the coolest namespaces.

I've been working on a simple workflow engine as an example codebase for exploring different aspects of object oriented programming (inheritance, encapsulation, polymorphism, design patterns, etc.) for training purposes.

As a side note, I've found that it's actually very difficult to describe good object oriented code; I can just kind of feel it when I'm writing it and I know it when I see it...but it's really, really hard to describe.  I was asked by an associate consultant why it mattered.  Why bother with good object oriented design?  For me (at least), more than anything, it's about organization of code, readability, maintainability, and usability.  Good object oriented code makes it easy to think about the models and how the interactions between the different moving parts are executed.  But that's a bigger topic for a different post.

Back on topic :-D The basic design scenario that I was trying to solve in this case is that the simple workflow engine (SWE) would have the capability of hydrating a workflow template instance from an XML definition file (much like WF does with .xoml files, but on a much more basic level, of course).  I thought this would be a good exercise for teaching purposes as it would cover various aspects of reflection.  Somewhere along the line, inspired by a comment by Richard Deeming (see bullet #4) on Rick Strahl's DataContextFactory implementation, I decided to see if I could do it using expression trees instead.

Here is a sample XML template definition:

<WorkflowTemplate>
    <Actions>
        <Action Type="SimpleWorkflowEngine.Extensions.CustomActions.EmailAction, 
            SimpleWorkflowEngine.Extensions">
            <Parameters>
                <Parameter Name="ContinueOnError">true</Parameter>
                <Parameter Name="FriendlyName">Send Email</Parameter>
                <Parameter Name="RecipientAddress">cchen@domain.com</Parameter>
                <Parameter Name="Message">Hello, World! From SimpleWorkflowEngine!</Parameter>
                <Parameter Name="Subject">Test Email</Parameter>
            </Parameters>
        </Action>
    </Actions>
</WorkflowTemplate>

Here are the classes which this XML deserializes to:

using System;
using System.Collections.ObjectModel;
using System.Xml.Serialization;

namespace SimpleWorkflowEngine.Core.Common
{
    /// <summary>
    /// Models a workflow template.
    /// </summary>
    [Serializable]
    [XmlRoot("WorkflowTemplate")]
    public class WorkflowTemplate
    {
        private Collection<WorkflowTemplateAction> _actions;

        /// <summary>
        /// Gets or sets the actions for this workflow template.
        /// </summary>
        /// <value>The actions.</value>
        [XmlArray("Actions"), XmlArrayItem("Action", 
            typeof(WorkflowTemplateAction))]
        public Collection<WorkflowTemplateAction> Actions
        {
            get { return _actions; }
            set { _actions = value; }
        }
    }

    /// <summary>
    /// Represents an action in the workflow.
    /// </summary>
    [Serializable]
    public class WorkflowTemplateAction
    {
        private string _typeName;
        private Collection<WorkflowTemplateParameter> _parameters;

        /// <summary>
        /// Gets or sets the type name of the concrete 
        /// <see cref="WorkflowAction"/> class.
        /// </summary>
        /// <value>
        /// The type name of the concrete <see cref="WorkflowAction"/> class.
        /// </value>
        [XmlAttribute("Type")]
        public string TypeName
        {
            get { return _typeName; }
            set { _typeName = value; }
        }

        /// <summary>
        /// Gets or sets the parameters which map to property values on 
        /// the action.
        /// </summary>
        /// <value>The parameters.</value>
        [XmlArray("Parameters"), XmlArrayItem("Parameter", 
            typeof(WorkflowTemplateParameter))]
        public Collection<WorkflowTemplateParameter> Parameters
        {
            get { return _parameters; }
            set { _parameters = value; }
        }
    }

    /// <summary>
    /// Represents a property value on the <see cref="WorkflowAction"/>.
    /// </summary>
    [Serializable]
    public class WorkflowTemplateParameter
    {
        private string _name;
        private string _value;

        /// <summary>
        /// Gets or sets the name.  It must match the name of the property.
        /// </summary>
        /// <value>The name of the property.</value>
        [XmlAttribute("Name")]
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        /// <summary>
        /// Gets or sets the value.
        /// </summary>
        /// <value>The value.</value>
        [XmlText(typeof(string))]
        public string Value
        {
            get { return _value; }
            set { _value = value; }
        }
    }
}

I've done something similar in a workflow engine that I put together for Zorch Software before the days of WF. Back then I used reflection to assemble a workflow instance from an XML template as well. (In that case, the engine supported state machine workflows; for this training sample, I thought that just sequential was good enough)

Here is the invocation code to get a new instance of a workflow from a workflow template definition:

using System;
using MbUnit.Framework;
using SimpleWorkflowEngine.Core.Common;
using SimpleWorkflowEngine.Core.Contracts;
using SimpleWorkflowEngine.Core.Runtime;

namespace SimpleWorkflowEngine.Tests.Fixtures
{
    [TestFixture]
    public class WorkflowFactoryTests
    {
        [Test]
        public void TestCreateInstance()
        {
            IWorkflowTemplateProvider provider =
                ApplicationContext.Instance.Resolve<IWorkflowTemplateProvider>();

            WorkflowTemplate template =
                provider.FromTemplateId(
                new Guid("1FE5526C-D0E7-4c58-8644-3B3144AEED0E"));

            Workflow instance = WorkflowFactory.Create(template);

            Assert.AreEqual(1, instance.Actions.Count);
        }
    }
}

The basics are that the factory has to create an instance by iterating through each WorkflowTemplateAction and creating a concrete WorkflowAction instance and set property values using the WorkflowTemplateParameter associated with the WorkflowTemplateAction.

Here is the implementation of the factory method (cool stuff in bold):

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using SimpleWorkflowEngine.Core.Common;

namespace SimpleWorkflowEngine.Core.Runtime
{
    /// <summary>
    /// Assembles a workflow instance based on an input template.
    /// </summary>
    public static class WorkflowFactory
    {
        private static string _nullPropertyError = 
            "The parameter \"{0}\" did not match a property on the class \"{1}\".";

        /// <summary>
        /// Assembles a workflow instance from a workflow template instance.
        /// </summary>
        /// <param name="template">The template.</param>
        /// <returns>A workflow instance based on the workflow template.</returns>
        public static Workflow Create(WorkflowTemplate template)
        {
            Workflow instance = new Workflow();

            foreach(WorkflowTemplateAction templateAction in template.Actions)
            {
                Type actionType = Type.GetType(templateAction.TypeName);               

                List<MemberBinding> bindings = new List<MemberBinding>();

                foreach(WorkflowTemplateParameter parameter in templateAction.Parameters)
                {
                    BindingFlags flags = BindingFlags.SetProperty 
                        | BindingFlags.Instance | BindingFlags.Public;

                    // Get the property matching the parameter name.
                    PropertyInfo property = actionType.GetProperty(
                        parameter.Name, flags);

                    if(property == null)
                    {
                        throw new NullReferenceException(string.Format(
                            _nullPropertyError, parameter.Name, actionType.Name));
                    }

                    // Convert the parameter value type.
                    object value = Convert.ChangeType(
                        parameter.Value, property.PropertyType);

                    // Create an assignment binding (set the property value).
                    MemberAssignment binding = Expression.Bind(
                        property, 
                        Expression.Constant(value, property.PropertyType));

                    bindings.Add(binding);
                }

                // Create the code expression and execute it to get a new instance.
                MemberInitExpression init = Expression.MemberInit(
                    Expression.New(actionType), bindings);

                WorkflowAction action = Expression.Lambda<Func<WorkflowAction>>(init)
                    .Compile().Invoke();

                // Add the action to the workflow.
                instance.Actions.Add(action);
            }

            return instance;
        }
    }
}

The outer for loop iterates the actions to create and the inner for loop collects the properties to set on the action.  Object creation and initializaiton is done in one shot using Expression.Lambda.

For reference, here is the target class for the XML in the sample above:

using System;
using SimpleWorkflowEngine.Core.Attributes;
using SimpleWorkflowEngine.Core.Common;
using SimpleWorkflowEngine.Core.Constants;
using SimpleWorkflowEngine.Extensions.Components;

namespace SimpleWorkflowEngine.Extensions.CustomActions
{
    /// <summary>
    /// A worflow action which sends an email to a recipient.
    /// </summary>
    public class EmailAction : WorkflowAction
    {
        private MailClientService _mailClientService;
        private string _message;
        private string _recipientAddress;
        private string _subject;

        /// <summary>
        /// Sets the mail client service.
        /// </summary>
        /// <value>The mail client service.</value>
        public MailClientService MailClientService
        {
            set { _mailClientService = value; }
        }

        /// <summary>
        /// Gets or sets the recipient address.
        /// </summary>
        /// <value>The recipient address.</value>
        [Parameter(Usage.IsRequired, "Recipient e-mail")]
        public string RecipientAddress
        {
            get { return _recipientAddress; }
            set { _recipientAddress = value; }
        }

        /// <summary>
        /// Gets or sets the message.
        /// </summary>
        /// <value>The message.</value>
        [Parameter(Usage.IsRequired, "Message")]
        public string Message
        {
            get { return _message; }
            set { _message = value; }
        }

        /// <summary>
        /// Gets or sets the subject.
        /// </summary>
        /// <value>The subject.</value>
        [Parameter(Usage.IsRequired, "Subject")]
        public string Subject
        {
            get { return _subject; }
            set { _subject = value; }
        }

        /// <summary>
        /// Gets a value indicating whether this instance 
        /// [requires input].
        /// </summary>
        /// <value>
        /// <c>true</c> if this instance [requires input]; 
        /// otherwise, <c>false</c>.
        /// </value>
        public override bool RequiresInput
        {
            get { return false; }
        }

        /// <summary>
        /// Inheriting member should override this method to implement 
        /// custom execution logic.
        /// </summary>
        /// <param name="context">The context.</param>
        protected override void OnExecute(ExecutionContext context)
        {
            if (_mailClientService == null)
            {
                throw new NullReferenceException(
                    "No mail service client is configured for this runtime.");
            }

            _mailClientService.SendMail(RecipientAddress, Subject, Message);
        }
    }
}

Admittedly, I didn't expect this to work...I had a hell of a time figuring out how to create the expression to set the property values.

 Tuesday, June 09, 2009

I Like Jeffrey Palermo's Prediction...

6/9/2009 12:15:49 PM (Eastern Daylight Time, UTC-04:00)

I've been playing around with ASP.NET MVC for about a week now and it does everything right that ASP.NET web forms did so wrong.  I've hated ASP.NET web forms with a passion as soon as I realized that the model was terrible for the majority of development shops in terms of managing unmanageable code jumbles -- huge methods written on event handlers...

Don't get me wrong, ASP.NET 1.0 was a huge step up from classic ASP, but it has exploded into this huge culture of control based RAD developers.  Not that you couldn't roll your own MVC pattern for ASP.NET, but having it as an officially supported development model should help bring more web developers out from the grips of the dark side.

Most consultants (even "senior" ones) simply take the quick-and-dirty route when it comes to ASP.NET web forms development, dragging and dropping controls all day long.  Not that it's a bad thing...for prototyping, but it quickly devolves into hard to manage, hard to maintain, and difficult to test codebases with very low levels of reusability.  This is especially true once you roll on junior or mid level developers to a web project.

Earlier in the year, Jeffrey Palermo predicted that MVC would replace web forms as the dominant web application development model on the .NET platform.  With the recent news of MVC 2, Palermo reasserts his prediction with even greater conviction.  I was already long convinced that ASP.NET web forms was a craptastic model for web application development, but I had some skepticism about MVC (after my pretty awesome experience with Django).  This past week has convinced me that MVC kicks ass and I hope that Jeffrey's prediction is right.

I wholeheartedly agree; I simply can't wait to dump ASP.NET web forms.

 Friday, June 05, 2009

T-SQL MERGE: My New Friend

6/5/2009 11:49:08 AM (Eastern Daylight Time, UTC-04:00)

As I was catching up on SQL 2008 this morning, I spent some time working with the T-SQL MERGE command, new in SQL 2008.  Most of the blogs and examples online are a bit terse, so I decided to write a simple sample.

Check it out:

--// Create our SOURCE table
DECLARE @t1 TABLE (
    id      int,
    name    nvarchar(16),
    email   nvarchar(32)
)

--// Create our TARGET table
DECLARE @t2 TABLE (
    id      int,
    name    nvarchar(16),
    email   nvarchar(32)
)

--// Insert values into SOURCE table
INSERT INTO @t1 VALUES (1, 'Charles Chen', 'charles.chen@domain.com')
INSERT INTO @t1 VALUES (2, 'Sandra Chen', 'sandra.chen@domain.com')
INSERT INTO @t1 VALUES (3, 'Brad Wright', 'brad.wright@domain.com')

--// Insert values into TARGET table
INSERT INTO @t2 VALUES (4, 'Brady Sines', 'brady.sines@domain.com')
INSERT INTO @t2 VALUES (1, '', '')

--// Select values from the TARGET table (just to verify)
SELECT * FROM @t2

--// Merge records from source to target
MERGE
    @t2 AS [target]
USING
    @t1 AS [source]
ON
    ([target].id = [source].id)
WHEN NOT MATCHED BY TARGET
    THEN
        INSERT(id, name, email)
        VALUES([source].id, [source].name, [source].email)
WHEN MATCHED
    THEN
        UPDATE SET
            [target].name = [source].name,
            [target].email = [source].email
--// Get the journal of actions
OUTPUT $action, inserted.*, deleted.*;

--// Grab the resultant table
SELECT * FROM @t2

And here are the results:

Awesome!  Admittedly, I'm still trying to come up with some legitimate uses for this in my day-to-day application programming :-D

 Thursday, June 04, 2009

QOTD

6/4/2009 2:16:25 PM (Eastern Daylight Time, UTC-04:00)

A friend passed along a quote the other day:

So I just picked up this book today....and found this quote in the forward: "The truth of the matter is, if you need to “save” your job, I can’t help you. This book isn’t about struggling to maintain the level of mediocrity required not to get fired. It’s about being awesome. It’s about winning. You don’t win a race by trying not to lose. And you don’t win at life by trying not to suck. Fortunately, the content of the book has never been about trying not to suck. I can’t think that way, and neither should you."

Thanks, Dan!

 Thursday, May 28, 2009

Visitor Pattern In C# 4.0

5/28/2009 3:19:17 PM (Eastern Daylight Time, UTC-04:00)

I've blogged about the Visitor pattern previously and using double dispatch to resolve .NET's inherent inability to resolve methods by parameter type at runtime.

As I was reading about C# 4.0's dynamic types, I started to wonder if this would mean that we could finally get a more concise implementation of the pattern.  My hunch was correct.

Here is the updated code listing (key changes bolded):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;

namespace VisitorPatternConsole
{
    public class Program
    {
        private static void Main(string[] args)
        {
            // NOTE: Using dynamic collections.
            Collection<dynamic> visitors 
				= new Collection<dynamic>();
            Collection<dynamic> pets 
				= new Collection<dynamic>();
 
            // Initialize the pets
            pets.Add(new Fish());
            pets.Add(new Dog());

            // Initialize the visitors
            visitors.Add(new Feeder());
            visitors.Add(new Walker());

            // Visit each of the pets.
            foreach (dynamic pet in pets)
            {
                foreach (dynamic visitor in visitors)
                {
                    visitor.Visit(pet);
                }
            }

            // Check the results.
            foreach (Pet pet in pets)
            {
                Console.Out.WriteLine(pet.GetType().Name);
                foreach (String note in pet.Visitors)
                {
                    Console.Out.WriteLine("\t{0}", note);
                }
            }
        }
    }

    /// <summary>
    /// Handles the base cases.
    /// </summary>
    public abstract class AbstractVisitor
    {
        public void Visit(Pet pet)
        {
            pet.Visitors.Add(
                "Not supported for this type of pet...");
        }
    }

    /// <summary>
    /// Concrete visitor, a pet feeder.
    /// </summary>
    public class Feeder : AbstractVisitor
    {
        public void Visit(Dog dog)
        {
            // Feed the dog
            dog.Visitors.Add("Fed the dog");
        }

        public void Visit(Fish fish)
        {
            // Feed the fish
            fish.Visitors.Add("Fed the fish");
        }
    }

    /// <summary>
    /// Concrete visitor, a pet walker.
    /// </summary>
    public class Walker : AbstractVisitor
    {
        public void Visit(Dog dog)
        {
            dog.Visitors.Add("Walked the dog");
        }

        // Fish can't be walked!
    }

    /// <summary>
    /// Base class for pets.
    /// </summary>
    public abstract class Pet
    {
        private readonly Collection<string> visitors;

        public Collection<string> Visitors
        {
            get { return visitors; }
        }

        protected Pet()
        {
            visitors = new Collection<string>();
        }
    }

    /// <summary>
    /// A pet fish.
    /// </summary>
    public class Fish : Pet { }

    /// <summary>
    /// A pet dog.
    /// </summary>
    public class Dog : Pet { }
}

Here is the output:

Wow, just when I thought dynamic was going to suck :-D

What is somewhat interesting is that both collections have to be declared of type dynamic; I'm still mulling this over, but it's not clear why it doesn't work if only one of the collections is declared dynamic (I figured that it should have worked if the visitors collection alone was declared dynamic).

 Wednesday, May 27, 2009

Random DevTools Entry #017

5/27/2009 6:27:01 PM (Eastern Daylight Time, UTC-04:00)

In software development, it's incredibly useful to be able to visualize your code interactions using sequence diagrams and data flow diagrams and what not.  Not only is the visualization a plus, the act of generating one helps tremendously in terms of working out the outline of the logic that you need to implement.  One of the biggest problems I've come across in this area are the tools: they're simply too heavy and too complex for general diagram drawing tasks in addition to being generally rigid as well.

Today, as I was about to download and install Visio, I decided to spend a few minutes checking to see if there was a web alternative.  Enter websequencediagrams.  This is an all around awesome little tool to add to your toolbox.  Not only is it free (free is always awesome), it's text based.  At first blush, this seems terrible; there's a whole syntax to learn and lots of typing.  But the syntax is incredibly easy and simple while powerful and easy to understand.

Here's an example (I've bolded the syntax to make it easier to distinguish):

Browser->App: HandleSearchClickEvent()
App->Service: ExecuteSearch(keyword)
activate Service
Service-->App: (return results)
deactivate Service
App->App: RenderResults(reseults)
note right of App:
    render URL with
    keyword in query string.
end note
App-->Browser: HTML
Browser-->Office: click:
http://../name.docx?term=keyword
Office->AddIn: ThisAddIn_Startup()
AddIn->AddIn: Check for search term
note left of AddIn:
    ActiveDocument.FullName will
    contain the query string.  This
    can be extracted with a regular
    expression
end note
AddIn->AddIn: Execute find

And here is the result:

There are also a variety of pre-defined styles you can choose to render your diagram.  It's all sorts of awesome and a real time-saver compared to traditional tools.  I personally love that it's text based; I've found that when working with Visio (and other such tools), more than half of my time is spent arranging things just to get them to line up.  A text based approach works well for sequence diagrams and gets rid of that layer of unnecessary complexity.

 Friday, April 17, 2009

WCF Load Balancing : An End To End Example For NetTcpBinding

4/17/2009 2:17:08 PM (Eastern Daylight Time, UTC-04:00)

Recently, I worked on prototyping WCF load balancing for our product, FirstPoint.  I built a simple example to test the configuration and behavior of load balancing.  Since there aren't many end-to-end examples of WCF load balancing on the web, I'm hoping this will be useful (since the Microsoft documentation on this is basically non-existent...well, for NetTcpBindings at least).

I will assume that you are already familiar with network load balancing and configuring the NLB on Windows Server 2003.

Here's a screenshot of how I've configured my network load balancer:

You'll notice that I've configured a specific port range for my service.  Also, take note of the cluster address: 192.168.1.220.  The two servers that make up the cluster are FPDEV1 (192.168.1.222) and FPDEV2 (192.168.1.223).

I've defined a simple service interface which simply echoes the message with a server name:

using System.ServiceModel;

namespace WcfLoadBalancingSample.Server.Contracts {
    /// <summary>
    /// A simple service contract definition which defines an echo operation.
    /// </summary>
    [ServiceContract(SessionMode = SessionMode.Allowed)]
    public interface IEchoService {

        /// <summary>
        /// Echoes the specified message.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <returns>The input message with a server identifier attached.</returns>
        [OperationContract]
        string Echo(string message);
    }
}

And here is the implementation:

using System;
using WcfLoadBalancingSample.Server.Contracts;

namespace WcfLoadBalancingSample.Server.Services {
    /// <summary>
    /// Implements the <c>IEchoService</c>.
    /// </summary>
    public class EchoService : IEchoService {
        #region IEchoService Members

        /// <summary>
        /// Echoes the specified message.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <returns>
        /// The input message with a server identifier attached.
        /// </returns>
        public string Echo(string message) {
            return string.Format("[{0}] {1}", Environment.MachineName, message);
        }

        #endregion
    }
}  

As you can see, I've simply prepended the machine name to each response so that we can track which server we are connecting to. Here is the main program which hosts the service:

using System;
using System.ServiceModel;
using WcfLoadBalancingSample.Server.Services;

namespace WcfLoadBalancingSample.Server {
    internal class Program {
        private static void Main(string[] args) {
            var program = new Program();
            program.Run();
        }

        public void Run() {           
            ServiceHost serviceHost = null;

            try {
                serviceHost = new ServiceHost(typeof (EchoService));
                serviceHost.Open();

                Console.Out.WriteLine("Service ready.");
                Console.Out.WriteLine("Press any key to terminate.");
                Console.Out.WriteLine("============================");
                Console.ReadKey();
            }
            catch (Exception exception) {
                Console.Out.WriteLine(exception);
                Console.ReadKey();
            }
            finally {
                if (serviceHost != null) {
                    serviceHost.Abort();
                }
            }
        }
    }
}  

This should be deployed on your each of your two (or more) servers in your cluster.  The magic comes next in the configuration file:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <services>
            <service name="WcfLoadBalancingSample.Server.Services.EchoService"
                     behaviorConfiguration="WcfLoadBalancingSample.Server.Services.EchoServiceBehavior">
                <!-- Service Endpoints -->
                <!--///
                    The configured endpoint address is the IP address of the load balanced
                    cluster.  The port number has been mapped to the cluster.
                ///-->
                <endpoint
                    address ="net.tcp://192.168.1.220:12345/lb/EchoService"
                    binding="customBinding"
                    bindingConfiguration="DefaultCustomBinding"
                    contract="WcfLoadBalancingSample.Server.Contracts.IEchoService">
                </endpoint>
            </service>
        </services>
        <bindings>
            <!--///
                A simple custom binding.  Note the leaseTimeout setting.
                This is referenced in the SDK documentation, but not described
                in any way as to how you're supposed to configure it.
            ///-->
            <customBinding>
                <binding name="DefaultCustomBinding">
                    <windowsStreamSecurity protectionLevel="None"/>
                    <binaryMessageEncoding/>
                    <tcpTransport>
                        <connectionPoolSettings leaseTimeout="00:00:01"/>
                    </tcpTransport>
                </binding>
            </customBinding>
        </bindings>
        <behaviors>
            <serviceBehaviors>
                <behavior name="WcfLoadBalancingSample.Server.Services.EchoServiceBehavior">
                    <serviceMetadata httpGetEnabled="True"
                                     httpGetUrl="http://192.168.1.220/lb/EchoService/MEX"/>
                    <serviceDebug includeExceptionDetailInFaults="True" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
    </system.serviceModel>
</configuration>

The most important part of this configuration file is the setting for the lease timeout. The SDK documentation references this setting, but does not go into detail on how it's configured.  Note that it seems that you can only set the least timeout value in configuration using a custom binding.

There is one particularly important thing to note here: I've set the timeout to 1 second for demonstration purposes only.  The SDK documentation mentions that this value should be set to 30 seconds.  As we'll see later, I have the client creating a new connection every 2.5 seconds (on purpose so we can test connectivity).  What I found was that with the default setting (5 minutes, according to the SDK), if you initially connect to server A and server A goes down, it will not automatically connect to server B.  I assume this is because of the lease timeout value (it throws an exception).

Also note that the endpoint is configured using the IP address of the node balancing cluster and not the individual servers.

The client side of it is pretty straight forward as well:

using System;
using System.Runtime.Remoting.Messaging;
using System.Threading;
using WcfLoadBalancingSample.Client.LoadBalancedService;

namespace WcfLoadBalancingSample.Client {
    public delegate void EchoDelegate();

    public class EchoEventArgs : EventArgs {
        public EchoEventArgs(string message) {
            Message = message;
        }

        public string Message { get; set; }
    }

    internal class Program {
        private static void Main(string[] args) {
            var program = new Program();
            program.Run();
        }

        public void Run() {
            // Start the server.
            Console.Out.WriteLine("Starting client...(press any key to exit)");

            // Start second thread to ping the server.
            EchoDelegate echoDelegate = EchoAsync;
            echoDelegate.BeginInvoke(EchoAsycCompleted, null);

            Console.Read();
        }
        
        /// <summary>
        /// Asynchronous execution of the call to the server.
        /// </summary>
        private void EchoAsync() {
            try {
                int count = 0;
                while (true) {
                    using (var serviceClient = new EchoServiceClient()) {
                        // Call the echo service.
                        string result = serviceClient.Echo(
                            count.ToString());

                        Console.Out.WriteLine(result);

                        count++;                        
                    }

                    Thread.Sleep(2500);
                }
            }
            catch (Exception exception) {
                Console.Out.WriteLine(exception);
            }
        }

        /// <summary>
        /// Handles the completion of the thread.
        /// </summary>
        /// <param name="result">The result.</param>
        private void EchoAsycCompleted(IAsyncResult result) {
            var r = (AsyncResult) result;
            var e = (EchoDelegate) r.AsyncDelegate;

            e.EndInvoke(r);
        }
    }
}

The only thing to note is that I used a delegate to spin off a second thread to make the call to the server.  Adding a reference to the server generates the following configuration file:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <netTcpBinding>
                <binding name="CustomBinding_IEchoService">
                    <security mode="Transport">
                        <transport clientCredentialType="Windows" 
                                   protectionLevel="None" />
                        <message clientCredentialType="Windows" />
                    </security>
                </binding>
            </netTcpBinding>
        </bindings>
        <client>
            <endpoint 
                address="net.tcp://192.168.1.220:12345/lb/EchoService"
                binding="netTcpBinding" 
                bindingConfiguration="CustomBinding_IEchoService"
                contract="LoadBalancedService.IEchoService" 
                name="CustomBinding_IEchoService">
                <identity>
                    <userPrincipalName value="Administrator@fpdev.com" />
                    <servicePrincipalName value="" />
                    <dns value="192.168.1.220" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

Note that on this side, the binding is generated as a netTcpBinding.

And that's it!  Deploy the service to your clustered servers and start the services and then start the client.  If your cluster has a bias towards one server, you will see that the messages will come from that server.  To test that it actually is load balancing, simply stop the service on that server and you should see that the output will be coming from the other server.  Here's an example:

You can see that after I stop the service on FPDEV1 at the third echo message, it flips over to FPDEV2!  Awesome!

Here's the full project (VS2008): WcfLoadBalancingSample.zip (16.89 KB)

 Thursday, April 16, 2009

Obama Says No To The Assault Weapons Ban

4/16/2009 9:04:57 PM (Eastern Daylight Time, UTC-04:00)

So can we stop the bitter tears for a bit?  Just a little?

http://www.msnbc.msn.com/id/30232095

U.S. president signals he won't seek reinstatement of assault weapons ban

MEXICO CITY - Acknowledging a Mexican drug war that is "sowing chaos in our communities," President Barack Obama signaled Thursday he will not seek the reinstatement of a U.S. assault weapons ban but instead step up enforcement of existing laws against taking such weapons across the border.
Despite a campaign promise to see the lapsed ban renewed, Obama was bowing to the reality that to do so would be unpopular in politically key U.S. states and among Republicans as well as some conservative Democrats.

RSS 2.0 Atom 1.0 CDF