Compare Objects from Tables in SpecFlow

Earlier this week, I wrote about how to create and populate objects from tables created in your SpecFlow scenarios. If the only reason you’re populating an object is to do a comparison, there’s an easier way: the CompareToInstance<T> method.

Similar to the previously discussed method, CreateInstance<T>, an object will be created using the properties contained in a table of values. The object properties will be matched ignoring case and whitespace. CompareToInstance allows you to provide an instance of the same type and does a property-by-property comparison. If any of the property values are different, a TechTalk.SpecFlow.Assist.ComparisonException is thrown with a message containing all differences that were found.

Here’s an example!

Scenario: Update a person name
	Given I have an existing person
	And I change the name to the following
		| first | middle | last  |
		| Ftest | Mtest  | Ltest |
	When I save the person
	And I retrieve person
	Then the name was changed to the following
		| first | middle | last  |
		| Ftest | Mtest  | Ltest |
// don't forget!
// using TechTalk.SpecFlow.Assist;

[Given(@"I change the name to the following")]
public void GivenIChangeTheNameToTheFollowing(Table table)
{
    var p = ScenarioContext.Current.Get<Person>();
    p.Name = table.CreateInstance<NameType>();
}

[Then(@"the name was changed to the following")]
public void ThenTheNameWasChangedToTheFollowing(Table table)
{
    var p = ScenarioContext.Current.Get<Person>();
    table.CompareToInstance<NameType>(p.Name);
}

Calling Steps From Steps in SpecFlow

Steps are the building blocks of SpecFlow. Each Given/When/Then line in a SpecFlow scenario represents a step, and steps should be reused across features and scenarios to test your application from different angles. When you’re building a low-level scenario, you may want to use very specific steps. In a higher-level feature, you may want to perform the same tasks but in a less granular fashion. Wouldn’t it be nice if you could create a “super-step” that just calls the necessary sub-steps?

Well, guess what? You can, and it’s really easy to do. First, let’s build some fake code to work with. I created a simple PersonRepository that lets me add and save Person objects. Here are the classes and my initial SpecFlow test.

Person.cs

using System;

namespace samples.SpecFlowDemo
{
    public class Person
    {
        public int Id { get; set; }

        public string Name { get; set; }

        public DateTime? DateOfBirth { get; set; }
    }
}

PersonRepository.cs

using System;
using System.Collections.Generic;

namespace samples.SpecFlowDemo
{
    public static class PersonRepository
    {
        private static readonly Dictionary<int, Person> Persons;

        static PersonRepository()
        {
            Persons = new Dictionary<int, Person>();
        }

        public static Person Get(int id)
        {
            if (!Persons.ContainsKey(id))
            {
                return null;
            }
            return Persons[id];
        }

        public static bool Save(Person person)
        {
            if (person == null)
            {
                return false;
            }
            if (!Persons.ContainsKey(person.Id))
            {
                Persons.Add(person.Id, person);
            }
            Persons[person.Id] = person;
            return true;
        }
    }
}

Person_Add.feature

Feature: Person_Add
	In order track person records
	As a records manager
	I need to add new persons

Scenario: Add a person
	Given I have a new person record with the following properties
		| id  | name   | date of birth |
		| 100 | Rodney | 2/20/1950     |
	When I save the person
	Then the person is saved successfully
	And I can retrieve the person by ID

Person_AddSteps.cs

using Microsoft.VisualStudio.TestTools.UnitTesting;
using TechTalk.SpecFlow;
using TechTalk.SpecFlow.Assist;

namespace samples.SpecFlowDemo.SpecFlow
{
    [Binding]
    public class Person_AddSteps
    {
        [Given(@"I have a new person record with the following properties")]
        public void GivenIHaveANewPersonRecordWithTheFollowingProperties(Table table)
        {
            ScenarioContext.Current.Set<Person>(
                table.CreateInstance<Person>());
        }
        
        [When(@"I save the person")]
        public void WhenISaveThePerson()
        {
            var r = PersonRepository.Save(
                ScenarioContext.Current.Get<Person>());
            ScenarioContext.Current.Set<bool>(r, "SaveResult");
        }
        
        [Then(@"the person is saved successfully")]
        public void ThenThePersonIsSavedSuccessfully()
        {
            Assert.IsTrue(
                ScenarioContext.Current.Get<bool>("SaveResult"),
                "SaveResult");
        }
        
        [Then(@"I can retrieve the person by ID")]
        public void ThenICanRetrieveThePersonByID()
        {
            var expected = ScenarioContext.Current.Get<Person>();
            var actual = PersonRepository.Get(expected.Id);
            Assert.AreSame(expected, actual);
        }
    }
}

Now let’s say I want to test the PersonRepository’s ability to update records. In order to update a record, the record needs to exist. I could reuse the add feature’s “I have a person” step with a provided table of properties and its “I save the person” step, but it would be nice if I didn’t have to call both of those steps and provide data each time I needed to do something with an existing record.

I can avoid the repetition by calling those steps from within a new step that I’ll create called “I have an existing person record.” Here’s the code for my update feature.

Person_Update.feature

Feature: Person_Update
	In order track person records
	As a records manager
	I need to update existing persons

Scenario: Update a person
	Given I have an existing person record
	When I change the person name to "Rocko"
	And I save the person
	Then the person is saved successfully
	And I can retrieve the person by ID
	And the person name was saved as "Rocko"

Person_UpdateSteps.cs (Note the highlighted lines. The only “gotcha” that I ran into is that the steps class must inherit from SpecFlow’s Steps class in order to access the Given/When/Then functions.)

using Microsoft.VisualStudio.TestTools.UnitTesting;
using TechTalk.SpecFlow;

namespace samples.SpecFlowDemo.SpecFlow
{
    [Binding]
    public class Person_UpdateSteps : Steps
    {
        [Given(@"I have an existing person record")]
        public void GivenIHaveAnExistingPersonRecord()
        {
            var header = new[] { "Field", "Value" };
            var t = new Table(header);
            t.AddRow("id", "100");
            t.AddRow("name", "Fred");
            t.AddRow("date of birth", "12/15/1990");

            Given("I have a new person record with the following properties", t);
            When("I save the person");
        }
        
        [When(@"I change the person name to ""(.*)""")]
        public void WhenIChangeThePersonNameTo(string p0)
        {
            var p = ScenarioContext.Current.Get<Person>();
            p.Name = p0;
        }
                
        [Then(@"the person name was saved as ""(.*)""")]
        public void ThenThePersonNameWasSavedAs(string p0)
        {
            var p = ScenarioContext.Current.Get<Person>();
            Assert.AreEqual(p0, p.Name);
        }
    }
}

You can read more about calling steps from step definitions in the SpecFlow documentation.

You can also download the code for this example from GitHub.

Abstract Classes and Generic Methods

I ran into a fun scenario where I passing an object that derived from an abstract base class into a generic static method where it would be passed on to another generic method for some special, type-specific processing. Everything worked great when I passed in an object declared as one of the derived types. However, when the object was declared as the abstract base type, it all fell apart because the generic method wanted to treat the object as the base type and not the actual, derived type!

Problem

Consider this re-invented version of the scenario. I have a static PatientRouter class that accepts injured Creatures. If the Creature is a Human, it will be routed to a HumanHospital. If it’s an Animal, it will be routed to an AnimalHospital. Note, however, that the code fails if a Creature object is received, even if the Creature is actually a Human or Animal. We need to do something so this Creature can be correctly cared for!

public static class PatientRouter
{
    public static void Route<T>(T creature) 
        where T : Creature
    {
        SendToHospital(creature);
    }

    public static void SendToHospital<T>(T creature)
        where T : Creature
    {
        if (typeof(T) == typeof(Creature))
        {
            throw new Exception("Unacceptable!");
        }
        if (typeof(T) == typeof(Human))
        {
            var h = new HumanHospital();
            h.CareFor(creature as Human);
        }
        if (typeof(T) == typeof(Animal))
        {
            var h = new AnimalHospital();
            h.CareFor(creature as Animal);
        }
    }
}

Solution

There are two options that I found for dealing with this scenario. The first is to use the dynamic keyword introduced in .NET Framework 4.0. Here’s what that might look like:

public static void Route<T>(T creature)
    where T : Creature
{
    dynamic d = creature;
    SendToHospital(d);
}

Unfortunately, .NET 4.0 wasn’t an option for me, though. I was, however, able to come up with an acceptable solution using reflection. I don’t love using reflection to execute a method like this, but it gets the job done–so I’m content to use it in a scenario like this until .NET 4.0 becomes available.

public static void Route<T>(T creature) 
    where T : Creature
{
    // using reflection
    typeof(PatientRouter)
        .GetMethod("SendToHospital")
        .MakeGenericMethod(creature.GetType())
        .Invoke(null, new[] { creature });
}

For reference, here’s the complete example with both solutions:

namespace samples.BaseClassGenericMethod
{
    using System;

    public abstract class Creature
    {
        public bool IsInjured { get; set; }
    }

    public class Human : Creature
    {
        /* human stuff */
    }

    public class Animal : Creature
    {
        /* animal stuff */
    }

    public interface IHospital<T> where T : Creature
    {
        void CareFor(T patient);
    }

    public class HumanHospital : IHospital<Human>
    {
        public void CareFor(Human patient)
        {
            Console.WriteLine("Caring for human!");
        }
    }

    public class AnimalHospital : IHospital<Animal>
    {
        public void CareFor(Animal patient)
        {
            Console.WriteLine("Caring for animal!");
        }
    }

    public static class PatientRouter
    {
        public static void Route<T>(T creature) 
            where T : Creature
        {
            // base case
            SendToHospital(creature);

            // using dynamic (.NET 4.0)
            //dynamic d = creature;
            //SendToHospital(d);

            // using reflection
            //var h = typeof(PatientRouter)
            //    .GetMethod("SendToHospital")
            //    .MakeGenericMethod(creature.GetType())
            //    .Invoke(null, new[] { creature });
        }

        public static void SendToHospital<T>(T creature)
            where T : Creature
        {
            if (typeof(T) == typeof(Creature))
            {
                throw new Exception("Unacceptable!");
            }
            if (typeof(T) == typeof(Human))
            {
                var h = new HumanHospital();
                h.CareFor(creature as Human);
            }
            if (typeof(T) == typeof(Animal))
            {
                var h = new AnimalHospital();
                h.CareFor(creature as Animal);
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var h = new Human();
            PatientRouter.Route(h);

            var a = new Animal();
            PatientRouter.Route(a);

            Creature c = new Human();
            PatientRouter.Route(c);

            Console.ReadLine();
        }
    }
}

Create and Populate Objects in SpecFlow Scenarios

SpecFlow is definitely my favorite new tool for 2012. If you haven’t checked it out yet, you should. If you’ve checked it out and still don’t get it, come talk to me. I love writing scenarios using business language to help guide my test-driven development. The integration-level tests are proving to be an awesome supplement to more traditional isolated unit tests.

Sometimes it’s hard to come up with a good scenario step because you need to specify several details. Don’t worry, though–SpecFlow’s got ya covered with its Assist Helpers. Let’s say I’m working on some code that has a configuration object that contains my application’s settings. When I’m writing a feature scenario, I might want to provide these settings. I can do just that by putting the details into a table in my scenario.

Configuration.cs

public class Configuration
{
    public string OutputDir { get; set; }
    public bool Enabled { get; set; }
}

Feature1.feature

Scenario: CreateInstance demo
    Given I have the following configuration
        | output dir | enabled |
        | c:\blah    | true    |
    When I do something
    Then what I expected to happen happened

In my step definition, I can import the TechTalk.SpecFlow.Assist namespace to use Assist Helpers like the CreateInstance&lt;T&gt; extension method. When called on a table, CreateInstance will match columns to properties to create and populate an object. Here’s how I use it with the above example:

[Given(@"I have the following configuration")]
public void GivenIHaveTheFollowingConfiguration(Table table)
{
    var config = table.CreateInstance();
}

When creating the object, case-sensitivity and whitespace are ignored, allowing you to create a human-friendly table of your object’s property values. You can also use a vertical table with properties listed as rows. This table will produce the same result as above:

Scenario: CreateInstance demo
    Given I have the following configuration
        | Field      | Value   |
        | output dir | c:\blah |
        | enabled    | true    |
    When I do something
    Then what I expected to happen happened

This technique allows you to create complex objects without having to write any code. You can create highly re-usable steps that rely on the scenario author to provide necessary details in the scenario itself. Simply awesome!

Stubs in Microsoft Fakes

A few weeks back, I wrote an article about using shims in Microsoft Fakes. In addition to shims, Microsoft Fakes also has support for stubs. Stubs in Microsoft Fakes works a lot like other mocking frameworks such as Rhino Mocks, and it comes with a lot of the same limitations (must be visible, must be virtual, etc.). Let’s look at an example of what we can do using stubs in Microsoft Fakes. (Note: Microsoft Fakes requires Visual Studio 2012.)

Before we can use Microsoft Fakes, we need to do a little setup. Here are the steps that need to be performed:

  1. Create a new solution/project; I’m using a C# Console Application named “FakesSample”
  2. Add a new Unit Test Project to the solution; mine is named “FakesSample.Tests”
  3. Add a reference to the project to be tested in the test project
  4. In Solution Explorer, right-click the newly created reference and choose Add Fakes Assembly

And we’ll need some code to test. This is what I’ll be using:

namespace adamprescott.net.FakesSample
{
    using System;

    public class Mammal
    {
        public string Name { get; set; }
    }

    public interface IDataAccess
    {
        Mammal Get(int id);
    }

    public class Program
    {
        static void Main(string[] args)
        {
            var p = new Program();
            p.Run();
        }

        public IDataAccess DataAccess { get; set; }

        public void Run()
        {
            var m = DataAccess.Get(1);
            Console.WriteLine(m.Name);
        }
    }
}

Create a stub

The core functionality of a stub in unit tests is to remove external dependencies and/or provide makeshift functionality. In our code above, there is an IDataAccess that’s used to retrieve Mammal objects by ID. The Microsoft Fakes stub is perfect for this. In code, we create a Mammal object to be returned, and we return it using a lambda in our stub:

var m = new Mammal { Name = "Terry" };
var stubDataAccess = new StubIDataAccess
{
    GetInt32 = x =&gt; m
};

Verify a call

The stub gives us our desired behavior, but how do we know the stub was used? We can add verification by setting a flag in our stub implementation and asserting the value after the test is executed.

var m = new Mammal { Name = "Terry" };
var wasCalled = false;
var stubDataAccess = new StubIDataAccess
{
    GetInt32 = x =&gt; {
        wasCalled = true;
        return m;
    }
};
// ...
Assert.IsTrue(wasCalled);

I like that Microsoft Fakes makes this capability available without the need of a third party, but I’ll probably be sticking with Rhino Mocks for the time being. I haven’t found anything that I couldn’t do in MS Fakes that I could do with Rhino Mocks, but it often takes a lot more code. Maybe it’s because I’m less familiar with Fakes, or maybe it’s because Rhino Mocks is a more mature mocking framework–I’m not sure.

Here’s the complete unit test example:

namespace adamprescott.net.FakesSample.Tests
{
    using adamprescott.net.FakesSample.Fakes;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class ProgramTest
    {
        [TestMethod]
        public void RunWritesNameToConsole()
        {
            // Arrange
            var target = new Program();

            var m = new Mammal { Name = "Terry" };
            var wasCalled = false;
            var stubDataAccess = new StubIDataAccess
            {
                GetInt32 = x =&gt;
                {
                    wasCalled = true;
                    return m;
                }
            };
            target.DataAccess = stubDataAccess;

            // Act
            target.Run();

            // Assert
            Assert.IsTrue(wasCalled);
        }
    }
}

Joins in LINQ

The scenario: you have two related collections of objects, and you need to smush ’em together into a collection of combined records. It’s easy to do with LINQ’s Join method, but Join can seem a little intimidating–just check out its declaration:

// yikes!
public static IEnumerable Join<TOuter, TInner, TKey, TResult>(
	this IEnumerable<TOuter> outer,
	IEnumerable<TInner> inner,
	Func<TOuter, TKey> outerKeySelector,
	Func<TInner, TKey> innerKeySelector,
	Func<TOuter, TInner, TResult> resultSelector
)

It’s really not so bad, though. Here’s the breakdown:

  • “this IEnumerable<TOuter> outer” what you’re joining from
  • “IEnumerable<TInner> inner” what you’re joining to
  • “Func<TOuter, TKey> outerKeySelector” an expression for how to match the ‘from’ records
  • “Func<TInner, TKey> innerKeySelector” an expression for how to match the ‘to’ records
  • “Func<TOuter, TInner, TResult> resultSelector” an expression for the joined result

Still sounds rough? Let’s look at an easy example:

class Person
{
	public string Name;
	public string Occupation;
}

class Job
{
	public string Name;
	public decimal Salary;
}

void Main()
{
	var people = new[]
	{
		new Person { Name = "Adam", Occupation = "Blogger" },
		new Person { Name = "Joe", Occupation = "Teacher" },
		new Person { Name = "Hilary", Occupation = "Actress" }
	};
	var jobs = new[]
	{
		new Job { Name = "Blogger", Salary = 0.0m },
		new Job { Name = "Teacher", Salary = 100.0m },
		new Job { Name = "Actress", Salary = 5000.0m }
	};

	var salaryByPerson = people.Join(
		jobs,
		p => p.Occupation,
		j => j.Name,
		(p,j) => new { Person = p.Name, Salary = j.Salary });

	foreach (var sbp in salaryByPerson)
	{
		Console.WriteLine("Person: {0}, Salary: {1}",
			sbp.Person,
			sbp.Salary.ToString("c"));
	}
}

/* Output
Person: Adam, Salary: $0.00
Person: Joe, Salary: $100.00
Person: Hilary, Salary: $5,000.00
*/

The Join in the above example is equivalent to SQL like this:

SELECT p.Name AS Person, j.Salary
FROM people p
JOIN jobs j ON p.Occupation=j.Name

Now you’ve got it, right? Yea!

ScenarioContext in SpecFlow

I’ve been using SpecFlow pretty regularly for a few weeks now, and I must say, I’m a fan. I find that it’s a lot easier to do test-first development because I’m writing the test in human-readable, business language.

One of the ideas that I didn’t understand right away was how to re-use generated step definitions across features and scenarios. ScenarioContext and FeatureContext give you great options to handle this, though. Let’s check out an example using a modified version of the default scenario SpecFlow generates with a new feature file:

Scenario: Add two numbers
	Given I enter 50 into the calculator
	And I press plus
	And I enter 70 into the calculator
	When I press enter
	Then the result should be 120 be displayed

When I generate step definitions, I might end up with a class that looks like this:

namespace adamprescott.net.Calculator.SpecFlow
{
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using TechTalk.SpecFlow;

    [Binding]
    public class Calculator_AddSteps
    {
        Calculator calculator = new Calculator();

        [Given(@"I enter (.*) into the calculator")]
        public void GivenIEnterIntoTheCalculator(int p0)
        {
            calculator.Number(p0);
        }

        [Given(@"I press plus")]
        public void GivenIPressPlus()
        {
            calculator.Plus();
        }

        [When(@"I press enter")]
        public void WhenIPressEnter()
        {
            calculator.Enter();
        }

        [Then(@"the result should be (.*) be displayed")]
        public void ThenTheResultShouldBeBeDisplayed(int p0)
        {
            Assert.AreEqual(Convert.ToString(p0), calculator.Display);
        }
    }
}

Okay, not bad. A logical next feature might be subtraction. Some of the steps, like entering numbers and pressing enter, are shared. It would be nice if we could re-use those, but they’re configured to manipulate private variables in the Calculator_AddSteps class. So let’s do some refactoring! Instead of using a member-level variable, I can store my Calculator object in the ScenarioContext, making it accessible to other steps being executed in the same scenario.

// store to ScenarioContext like this:
ScenarioContext.Current.Set<Calculator>(new Calculator());
ScenarioContext.Current.Set<Calculator>(new Calculator(), "Calc");
ScenarioContext.Current["Calc"] = new Calculator();

// retrieve from ScenarioContext like this:
var c = ScenarioContext.Current.Get<Calculator>();
var c = ScenarioContext.Current.Get<Calculator>("Calc");
var c = ScenarioContext.Current["Calc"] as Calculator;

This is overkill for such a simple example, but I separated my shared steps into a new step definitions file. The final solution has three classes for the step definitions: Calculator_AddSteps, Calculator_SubtractSteps, and Calculator_SharedSteps.

Here’s the final solution, broken up by file:

Calculator_Add.feature

Feature: Calculator_Add
	In order to avoid silly mistakes
	As a math idiot
	I want to be told the sum of two numbers

Background:
	Given I have a calculator

Scenario: Add two numbers
	Given I enter 50 into the calculator
	And I press plus
	And I enter 70 into the calculator
	When I press enter
	Then the result should be 120 be displayed

Calculator_AddSteps.cs

namespace adamprescott.net.Calculator.SpecFlow
{
    using TechTalk.SpecFlow;

    [Binding]
    public class Calculator_AddSteps
    {
        [Given(@"I press plus")]
        public void GivenIPressPlus()
        {
            ScenarioContext.Current.Get<Calculator>().Plus();
        }
    }
}

Calculator_SharedSteps.cs

namespace adamprescott.net.Calculator.SpecFlow
{
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using System;
    using TechTalk.SpecFlow;

    [Binding]
    public class Calculator_SharedSteps
    {
        [Given(@"I have a calculator")]
        public void GivenIHaveACalculator()
        {
            ScenarioContext.Current.Set<Calculator>(new Calculator());
        }

        [Given(@"I enter (.*) into the calculator")]
        public void GivenIEnterIntoTheCalculator(int p0)
        {
            ScenarioContext.Current.Get<Calculator>().Number(p0);
        }

        [When(@"I press enter")]
        public void WhenIPressEnter()
        {
            ScenarioContext.Current.Get<Calculator>().Enter();
        }

        [Then(@"the result should be (.*) be displayed")]
        public void ThenTheResultShouldBeBeDisplayed(int p0)
        {
            Assert.AreEqual(Convert.ToString(p0), ScenarioContext.Current.Get<Calculator>().Display);
        }
    }
}

Calculator_Subtract.feature

Feature: Calculator_Subtract
	In order to avoid silly mistakes
	As a math idiot
	I want to be told the difference between two numbers

Background:
	Given I have a calculator

Scenario: Subtract two numbers
	Given I enter 70 into the calculator
	And I press minus
	And I enter 50 into the calculator
	When I press enter
	Then the result should be 20 be displayed

Calculator_SubtractSteps.cs

namespace adamprescott.net.Calculator.SpecFlow
{
    using TechTalk.SpecFlow;

    [Binding]
    public class Calculator_SubtractSteps
    {
        [Given(@"I press minus")]
        public void GivenIPressMinus()
        {
            ScenarioContext.Current.Get<Calculator>().Minus();
        }
    }
}

.NET Rocks! Road Trip

.NET Rocks! is a popular internet talk show, and they’re taking the show on the road. Carl Franklin and Richard Campbell are traversing the country on their .NET Rocks! Visual Studio 2012 Launch Road Trip, making stops in over 37 different cities. I was able to attend their Detroit session in Southfield, MI yesterday. The event was hosted by the Great Lakes Area .NET User Group (with yummy BBQ provided by sponsor New World Systems), and it was a good time!

Carl gave a good talk and demo on creating modern, Windows Store app-style (formerly “metro-style”) apps. In the demo, a slick app was built to display and listen to .NET Rocks! shows using a simple web service. The code was minimal, but the app looked great thanks to the built-in styles–it was impressive to see how little code it takes to make a great looking Windows Store app.

Richard then took over and gave a talk about DevOps. DevOps blurs the line between IT professionals and developers, allowing them to coordinate efforts to evolve and improve applications over time. A big focus of this talk was on Microsoft System Center, Microsoft’s enterprise resource monitoring tool. System Center allows you to collect logs and events from different resources across the network and puts them into a consolidated view. New to System Center is the ability to hook into .NET apps, allowing you to specify and create events for things like methods that take too long. System Center can tie into TFS, so when an application event occurs, a work item can be created.

Third to take the stage was Microsoft’s Jeff Wilcox, independent creator of the popular Foursquare client 4th & Mayor. Jeff talked to us his experience with Microsoft, but most of the discussion was about 4th & Mayor. I’m not a Foursquare user, but I can appreciate what Jeff has done in creating this beautiful app with a focus on providing a great user experience. Jeff’s brief presentation was followed by a live taping of The Tablet Show, another offering from Franklin and Campbell.

It was a fun event. The food was great, it was entertaining, and I learned a few new things. Thanks to GANG for hosting and to .NET Rocks! for stopping by Detroit!

TransactionScope in Multi-Threaded Applications

Using the TransactionScope class is a terrific way to do implicit transactional programming. It’s incredibly simple, and transactions can span multiple operations across multiple connections.

Basic usage couldn’t be simpler:

using (var ts = new TransactionScope())
{
    // do transactional stuff

    ts.Complete();
}

I was working on an application that accepted a batch of items to be processed asynchronously. The desired behavior was to rollback everything if any individual items failed. I figured this would be a snap with TransactionScope. I wrapped the multi-threaded processing code in a TransactionScope, but it didn’t work. The problem is that the TransactionScope does not transcend application and thread boundaries, so the operations launched on a separate thread were executed outside the scope of the ambient transaction.

There is a relatively simple solution to this problem, though. A DependentTransaction can be created from the current transaction and passed into the sub-processes. Here is a simple example:

public void Parent()
{
    using (var ts = new TransactionScope())
    {
        ThreadPool.QueueUserWorkItem(
            Child,
            Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete);
        ts.Complete();
    }
}

public void Child(object o)
{
    var dtx = o as DependentTransaction;
    using (var ts = new TransactionScope(dtx))
    {
        // do transactional stuff

        ts.Complete();
    }
    dtx.Complete();
}

Resolve Generic Types at Runtime with Unity

I’m working on a small project that uses Unity to manage record type-specific data providers. As a brief overview, the project accepts a collection of objects. An appropriate data provider is retrieved for each object, and then the object is passed to that provider for processing.

I register the providers in a UnityContainer like so:

UnityContainer.RegisterType<IDataProvider<RecordType>, RecordTypeDataProvider>();

So, in a perfect world, I wanted to resolve the providers based on the type of each record in a collection. Something like this:

foreach (var record in collection)
{
    var provider = ResolveProvider(record);
    provider.Process(record);
}

The problem with this approach is that I need to resolve the type using the record’s type.

// what I want (invalid)
UnityContainer.Resolve<IDataProvider<record.GetType()>>();

Luckily, there’s a way to do this by using the Type.MakeGenericType method. Check it out:

var providerType = typeof(IDataProvider<>).MakeGenericType(record.GetType());
var provider = UnityContainer.Resolve(providerType);

This works, but it leaves me with another challenge. UnityContainer.Resolve returns an object, but I need an IDataProvider. The solution? A base interface containing the non-generic methods and properties. This allows me to resolve the data provider using the record type but still return a typed object. Here’s the complete solution:

public interface IDataProvider
{
    void Process(BaseType record);
}

public interface IDataProvider<T> : IDataProvider
    where T : BaseType
{
    void Process<T>(T record);
}

public class RecordTypeDataProvider : IDataProvider<RecordType>
{
	// IDataProvider.Process
	public void Process(BaseType record)
	{
		Process(record as RecordType);
	}

	// IDataProvider<RecordType>.Process
	public void Process<RecordType>(RecordType record)
	{
		// process it!
	}
}

public static class Broker
{
	private static readonly UnityContainer UnityContainer;

	static Broker()
	{
		UnityContainer = new UnityContainer();

		UnityContainer.RegisterType<IDataProvider<RecordType>, RecordTypeDataProvider>();
		// other providers...
	}

	private static IDataProvider Resolve(BaseType record)
	{
		var providerType = typeof(IDataProvider<>).MakeGenericType(record.GetType());
		return UnityContainer.Resolve(providerType) as IDataProvider;
	}

	public static void Process(IEnumerable<BaseType> collection)
	{
		foreach (var record in collection)
		{
			var provider = Resolve(record);
			provider.Process(record);
		}
	}
}