Workflow services and distributed transactions — argh!

When you need to use MS DTC its normal to go through a stage of mentally preparing for some frustrations along the way. At least I do, but what I want to talk about is a very specific issue that surfaced only when I mixed workflow services and distributed transactions.

Starting a workflow service in a transaction is fairly straightforward and natively supported by Workflow Foundation. See TransactedReceiveScope documentation and use of TransactedReceiveScope code sample for more information. However, there is a common usage scenario that may get you into trouble with no clear reason. Lets say you have an application using workflow services and is leveraging the default SQL Server workflow instance store available in AppFabric. Additionally, the same application stores its data in a SQL Server database which, and this is the critical part, is also on the same SQL Server instance.

With the previous scenario if you need to transactionally start a workflow service and interact with the application database in the same transaction, such as to store the instance identifier of the started workflow service, you may get bitten by a race condition that will trigger the following, not so helpful, error message: “Transaction context in use by another session.”

The following sample code illustrates the previously mentioned scenario.

using (var context = new TransactionScope()) {
    using (var connection = CreateSqlConnection()) {
        // Start workflow
        string instanceId = client.Initiate();

        // Opening the connection after workflow start
        // leads to a race condition that causes errors
        connection.Open();

        SaveInstanceId(connection, instanceId);
    }

    context.Complete();
}

Searching the web for the error message will give you a few hits but none is specific to this given scenario. For example, you have a MSDN page about Using the TransactionScope Class that references the message but doesn’t go into details about it, you’ll also find a couple of StackExchange questions mostly about this problem when using loopback linked servers which also does not apply and then — thank god — there is a MSDN blog post that explains the issue and makes the solution clear.

… when two or more separate SqlConnections from same process or even different processes attempt to simultaneously enlist in the same distributed transaction, one or more may fail to enlist and report an exception. The reason for this is the server side code has no tolerance for multiple concurrent enlist operations on the same transaction, it will just immediately fail one of them. Server will not try to wait for a little and try again, server will not queue the requests, it will just immediately fail the conflicting one. So far the SQL Product team has no plans to support this functionality (simultaneously enlist two different connections in the same distributed) right now.
Freist Li, System.Transaction may fail in multiple-thread environment

With knowledge about the root cause it is now possible to update the sample code to make sure that the connection to the application database is not opened at exactly the same time as the connection opened by workflow runtime to persist the workflow in the instance store. The following sample code illustrates the fix:

using (var context = new TransactionScope()) {
    using (var connection = CreateSqlConnection()) {
        // Opening the connection before workflow start
        // eliminates the race condition
        connection.Open();

        // Start workflow
        string instanceId = client.Initiate();

        SaveInstanceId(connection, instanceId);
    }

    context.Complete();
}

This problem occurs at least in SQL Server 2008 R2, but judging by the blog post mentioned above this is a behavior that it’s not likely to change so it may also surface in more recent versions. A full sample application that illustrates the issue and can be used to test the behavior of more recent SQL Server versions is available at WFTransactions repository. Just remember that this is a race condition so even the wrong code will work most of the times.

Advertisements

Structuring your .NET solution on the file system

This is probably a subject at the same level of controversy as the one about where to put those pesky curly braces but let’s try setting personal preferences aside and look at it in an objective way.

It’s a fact that developers love consistency or at least in my opinion if they don’t then it is a disqualifying criteria in any job interview. However, another thing that developers tend to love is their own sense of consistency, basically they love being consistent in the way they like the best so it is important to pick one approach and make everyone stick to it.

When it comes to structuring a .NET solution in the filesystem I generally see two approaches being used:

  1. Hierarchical;
  2. Mostly flat.

In the first one its typical to see each part of a project name map to a physical folder, in this scenario, for Contoso.Web.Controls.[cs|k]proj you would expect to find the code in Contoso\Web\Controls\ path. In the mostly flat camp, the code for the previously mentioned project would be found at a folder named Contoso.Web.Controls\.

I’m in the mostly flat camp because I value that the number of parts in a project name does not affect the level at which it will be physically located. This tends to simplify things a lot when it comes to working with the filesystem structure either in build scripts or just for setting common output folders.

Another reason in favor of the mostly flat structure is that it aligns best with what we see more in the .NET open source community, see EntityFramework or ASP. NET MVC. This second part is specially important now that .NET itself made significant steps to become an open source framework.

Couple this second approach with the structure proposed by David Fowler and you have a quick set of rules that will allow you to be consistent within your project while at the same time following the overall trend in the .NET ecosystem.

A Different Kind of Assembly Hell

An assembly is first and foremost a deployment unit, they should normally be used to group code that works together and is deployed together or putting it the other way around, they are used to split code that may not be deployed together.

There are reasons to split code between multiple assemblies even if you intend to deploy them together but these are exceptions to the rule. I would see independent versioning requirements as one possible exceptional reason.

What you really shouldn’t do is create assemblies just for the sake of splitting your code for cosmetic reasons. I’m not saying that you shouldn’t organize your code, just saying there are better tools for that job. In this case, that would be namespaces alongside project folders and while on the subject of namespaces, another thing that really does not make any sense is to try to have a single namespace per assembly. If you’re down that path, take a step back cause you’re doing it wrong…

I saw, more than one time, .NET solutions suffer from this assembly explosion and quickly escalating to the hundreds of assemblies for something that it sure as hell wasn’t that complex and where 80% of the assemblies end up being deployed together due to a high level of dependencies.

However, you also need to avoid doing the opposite and cram everything in a single assembly. As pretty much everything in software development the correct answer depends on many things specific to the scenario at hand.

Be conscious of your decisions and why you make them.

Unit Testing DateTime – The Crazy Way

We all know that the process of unit testing code that depends on DateTime, particularly the current time provided through the static properties (Now, UtcNow and Today), it’s a PITA.

If you go ask how to unit test DateTime.Now on stackoverflow I’ll bet that you’ll get two kind of answers:

  1. Encapsulate the current time in your own interface and use a standard mocking framework;
  2. Pull out the big guns like Typemock Isolator, JustMock or Microsoft Moles/Fakes and mock the static property directly.

Now each alternative has is pros and cons and I would have to say that I glean more to the second approach because the first adds a layer of abstraction just for the sake of testability. However, the second approach depends on commercial tools that not every shop wants to buy or in the not so friendly Microsoft Moles. (Sidenote: Moles is now named Fakes and it will ship with VS 2012)

This tends to leave people without an acceptable and simple solution so after reading another of these types of questions in SO I came up with yet another alternative, one based on the first alternative that I presented here but tries really hard to not get in your way with yet another layer of abstraction.

So, without further dues, I present you, the Tardis. The Tardis is single section of conditionally compiled code that overrides the meaning of the DateTime expression inside a single class. You still get the normal coding experience of using DateTime all over the place, but in a DEBUG compilation your tests will be able to mock every static method or property of the DateTime class.

An example follows, while the full Tardis code can be downloaded from GitHub:

using System;
using NSubstitute;
using NUnit.Framework;
using Tardis;

public class Example
{
    public Example()
        : this(string.Empty) { }

    public Example(string title)
    {
#if DEBUG
        this.DateTime = DateTimeProvider.Default;
        this.Initialize(title);
    }

    internal IDateTimeProvider DateTime { get; set; }

    internal Example(string title, IDateTimeProvider provider)
    {
        this.DateTime = provider;
#endif
        this.Initialize(title);
    }

    private void Initialize(string title)
    {
        this.Title = title;
        this.CreatedAt = DateTime.UtcNow;
    }

    private string title;

    public string Title
    {
        get { return this.title; }
        set
        {
            this.title = value;
            this.UpdatedAt = DateTime.UtcNow;
        }
    }

    public DateTime CreatedAt { get; private set; }
    public DateTime UpdatedAt { get; private set; }
}

public class TExample
{
    public void T001()
    {
        // Arrange
        var tardis = Substitute.For<IDateTimeProvider>();
        tardis.UtcNow.Returns(new DateTime(2000, 1, 1, 6, 6, 6));

        // Act
        var sut = new Example("Title", tardis);

        // Assert
        Assert.That(sut.CreatedAt, Is.EqualTo(tardis.UtcNow));
    }

    public void T002()
    {
        // Arrange
        var tardis = Substitute.For<IDateTimeProvider>();
        var sut = new Example("Title", tardis);
        tardis.UtcNow.Returns(new DateTime(2000, 1, 1, 6, 6, 6));

        // Act
        sut.Title = "Updated";

        // Assert
        Assert.That(sut.UpdatedAt, Is.EqualTo(tardis.UtcNow));
    }
}

This approach is also suitable for other similar classes with commonly used static methods or properties like the ConfigurationManager class.

Extended Logging with Caller Info Attributes

.NET 4.5 caller info attributes may be one of those features that do not get much airtime, but nonetheless are a great addition to the framework.

These attributes will allow you to programmatically access information about the caller of a given method, more specifically, the code file full path, the member name of the caller and the line number at which the method was called.

They are implemented by taking advantage of C# 4.0 optional parameters and are a compile time feature so as an added bonus the returned member name is not affected by obfuscation.

The main usage scenario will be for tracing and debugging routines as will see right now. In this sample code I’ll be using NLog, but the example is also applicable to other logging frameworks like log4net.

First an helper class, without any dependencies and that can be used anywhere to obtain caller information:

using System;
using System.IO;
using System.Runtime.CompilerServices;

public sealed class CallerInfo
{
    private CallerInfo(string filePath, string memberName, int lineNumber)
    {
        this.FilePath = filePath;
        this.MemberName = memberName;
        this.LineNumber = lineNumber;
    }

    public static CallerInfo Create(
        [CallerFilePath] string filePath = "",
        [CallerMemberName] string memberName = "",
        [CallerLineNumber] int lineNumber = 0)
    {
        return new CallerInfo(filePath, memberName, lineNumber);
    }

    public string FilePath { get; private set; }

    public string FileName
    {
        get
        {
            return this.fileName ?? (this.fileName = Path.GetFileName(this.FilePath));
        }
    }

    public string MemberName { get; private set; }

    public int LineNumber { get; private set; }

    public override string ToString()
    {
        return string.Concat(this.FilePath, "|", this.MemberName, "|", this.LineNumber);
    }

    private string fileName;
}

Then an extension class specific for NLog Logger:

using System;
using System.Runtime.CompilerServices;
using NLog;

public static class LoggerExtensions
{
    public static void TraceMemberEntry(
        this Logger logger,
        [CallerFilePath] string filePath = "",
        [CallerMemberName] string memberName = "",
        [CallerLineNumber] int lineNumber = 0)
    {
        LogMemberEntry(logger, LogLevel.Trace, filePath, memberName, lineNumber);
    }

    public static void TraceMemberExit(
        this Logger logger,
        [CallerFilePath] string filePath = "",
        [CallerMemberName] string memberName = "",
        [CallerLineNumber] int lineNumber = 0)
    {
        LogMemberExit(logger, LogLevel.Trace, filePath, memberName, lineNumber);
    }

    public static void DebugMemberEntry(
        this Logger logger,
        [CallerFilePath] string filePath = "",
        [CallerMemberName] string memberName = "",
        [CallerLineNumber] int lineNumber = 0)
    {
        LogMemberEntry(logger, LogLevel.Debug, filePath, memberName, lineNumber);
    }

    public static void DebugMemberExit(
        this Logger logger,
        [CallerFilePath] string filePath = "",
        [CallerMemberName] string memberName = "",
        [CallerLineNumber] int lineNumber = 0)
    {
        LogMemberExit(logger, LogLevel.Debug, filePath, memberName, lineNumber);
    }

    public static void LogMemberEntry(
        this Logger logger,
        LogLevel logLevel,
        [CallerFilePath] string filePath = "",
        [CallerMemberName] string memberName = "",
        [CallerLineNumber] int lineNumber = 0)
    {
        const string MsgFormat = "Entering member {1} at line {2}";

        InternalLog(logger, logLevel, MsgFormat, filePath, memberName, lineNumber);
    }

    public static void LogMemberExit(
        this Logger logger,
        LogLevel logLevel,
        [CallerFilePath] string filePath = "",
        [CallerMemberName] string memberName = "",
        [CallerLineNumber] int lineNumber = 0)
    {
        const string MsgFormat = "Exiting member {1} at line {2}";

        InternalLog(logger, logLevel, MsgFormat, filePath, memberName, lineNumber);
    }

    private static void InternalLog(
        Logger logger,
        LogLevel logLevel,
        string format,
        string filePath,
        string memberName,
        int lineNumber)
    {
        if (logger == null)
            throw new ArgumentNullException("logger");

        if (logLevel == null)
            throw new ArgumentNullException("logLevel");

        logger.Log(logLevel, format, filePath, memberName, lineNumber);
    }
}

Finally an usage example:

using NLog;

internal static class Program
{
    private static readonly Logger Logger = LogManager.GetCurrentClassLogger();

    private static void Main(string[] args)
    {
        Logger.TraceMemberEntry();

        // Compile time feature
        //   Next three lines output the same except for line number
        Logger.Trace(CallerInfo.Create().ToString());
        Logger.Trace(() => CallerInfo.Create().ToString());
        Logger.Trace(delegate() { return CallerInfo.Create().ToString(); });

        Logger.TraceMemberExit();
    }
}

NOTE: Code for helper class and Logger extension also available here.

An Unusual UpdatePanel

The code you are about to see was mostly to prove a point, to myself, and probably has limited applicability. Nonetheless, in the remote possibility this is useful to someone here it goes…

So this is a control that acts like a normal UpdatePanel where all child controls are registered as postback triggers except for a single control specified by the TriggerControlID property. You could basically achieve the same thing by registering all controls as postback triggers in the regular UpdatePanel. However with this, that process is performed automatically.

Finally, here is the code:

public sealed class SingleAsyncTriggerUpdatePanel : WebControl, INamingContainer
{
    public string TriggerControlID { get; set; }

    [TemplateInstance(TemplateInstance.Single)]
    [PersistenceMode(PersistenceMode.InnerProperty)]
    public ITemplate ContentTemplate { get; set; }

    public override ControlCollection Controls
    {
        get
        {
            this.EnsureChildControls();

            return base.Controls;
        }
    }

    protected override void CreateChildControls()
    {
        if (string.IsNullOrWhiteSpace(this.TriggerControlID))
            throw new InvalidOperationException(
                "The TriggerControlId property must be set.");

        this.Controls.Clear();

        var updatePanel = new UpdatePanel()
        {
            ID = string.Concat(this.ID, "InnerUpdatePanel"),
            ChildrenAsTriggers = false,
            UpdateMode = UpdatePanelUpdateMode.Conditional,
            ContentTemplate = this.ContentTemplate
        };

        updatePanel.Triggers.Add(new SingleControlAsyncUpdatePanelTrigger
        {
            ControlID = this.TriggerControlID
        });

        this.Controls.Add(updatePanel);
    }
}

internal sealed class SingleControlAsyncUpdatePanelTrigger : UpdatePanelControlTrigger
{
    private Control target;

    private ScriptManager scriptManager;

    public Control Target
        {
            get
            {
                if (this.target == null)
                {
                    this.target = this.FindTargetControl(true);
                }

                return this.target;
            }
        }

    public ScriptManager ScriptManager
        {
            get
            {
                if (this.scriptManager == null)
                {
                    var page = base.Owner.Page;

                    if (page != null)
                    {
                        this.scriptManager = ScriptManager.GetCurrent(page);
                    }
                }

                return this.scriptManager;
            }
        }

    protected override bool HasTriggered()
    {
        string asyncPostBackSourceElementID = this.ScriptManager.AsyncPostBackSourceElementID;

        if (asyncPostBackSourceElementID == this.Target.UniqueID)
            return true;

        return asyncPostBackSourceElementID.StartsWith(
            string.Concat(this.target.UniqueID, "$"),
            StringComparison.Ordinal);
    }

    protected override void Initialize()
    {
        base.Initialize();

        foreach (Control control in FlattenControlHierarchy(this.Owner.Controls))
        {
            if (control == this.Target)
                continue;

            bool isApplicableControl = false;
            isApplicableControl |= control is INamingContainer;
            isApplicableControl |= control is IPostBackDataHandler;
            isApplicableControl |= control is IPostBackEventHandler;

            if (isApplicableControl)
            {
                this.ScriptManager.RegisterPostBackControl(control);
            }
        }
    }

    private static IEnumerable<Control> FlattenControlHierarchy(
        ControlCollection collection)
    {
        foreach (Control control in collection)
        {
            yield return control;

            if (control.Controls.Count > 0)
            {
                foreach (Control child in FlattenControlHierarchy(control.Controls))
                {
                    yield return child;
                }
            }
        }
    }
}

You can use it like this, meaning that only the B2 button will trigger an async postback:

<cc:SingleAsyncTriggerUpdatePanel ID="Test" runat="server" TriggerControlID="B2">
    <ContentTemplate>
        <asp:Button ID="B1" Text="B1" runat="server" OnClick="Button_Click" />
        <asp:Button ID="B2" Text="B2" runat="server" OnClick="Button_Click" />
        <asp:Button ID="B3" Text="B3" runat="server" OnClick="Button_Click" />
        <asp:Label ID="LInner" Text="LInner" runat="server" />
    </ContentTemplate>
</cc:SingleAsyncTriggerUpdatePanel>

ASP.NET ViewState Tips and Tricks #2

If you need to store complex types in ViewState DO implement IStateManager to control view state persistence and reduce its size. By default a serializable object will be fully stored in view state using BinaryFormatter.

A quick comparison for a complex type with two integers and one string property produces the following results measured using ASP.NET tracing:

BinaryFormatter: 328 bytes in view state
IStateManager: 28 bytes in view state

BinaryFormatter sample code:

// DO NOT
[Serializable]
public class Info
{
    public int Id { get; set; }

    public string Name { get; set; }

    public int Age { get; set; }
}

public class ExampleControl : WebControl
{
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        if (!this.Page.IsPostBack)
        {
            this.User = new Info { Id = 1, Name = "John Doe", Age = 27 };
        }
    }

    public Info User
    {
        get
        {
            object o = this.ViewState["Example_User"];

            if (o == null)
                return null;

            return (Info)o;
        }
        set { this.ViewState["Example_User"] = value; }
    }
}

IStateManager sample code:

// DO
public class Info : IStateManager
{
    public int Id { get; set; }

    public string Name { get; set; }

    public int Age { get; set; }

    private bool isTrackingViewState;

    bool IStateManager.IsTrackingViewState
    {
        get { return this.isTrackingViewState; }
    }

    void IStateManager.LoadViewState(object state)
    {
        var triplet = (Triplet)state;

        this.Id = (int)triplet.First;
        this.Name = (string)triplet.Second;
        this.Age = (int)triplet.Third;

    }

    object IStateManager.SaveViewState()
    {
        return new Triplet(this.Id, this.Name, this.Age);
    }

    void IStateManager.TrackViewState()
    {
        this.isTrackingViewState = true;
    }
}

public class ExampleControl : WebControl
{
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        if (!this.Page.IsPostBack)
        {
            this.User = new Info { Id = 1, Name = "John Doe", Age = 27 };
        }
    }

    public Info User { get; set; }

    protected override object SaveViewState()
    {
        return new Pair(
            ((IStateManager)this.User).SaveViewState(),
            base.SaveViewState());
    }

    protected override void LoadViewState(object savedState)
    {
        if (savedState != null)
        {
            var pair = (Pair)savedState;

            this.User = new Info();

            ((IStateManager)this.User).LoadViewState(pair.First);

            base.LoadViewState(pair.Second);
        }
    }
}