Jump-start Your Mind

I haven’t written in a while mostly because I’ve spent my time reading what others wrote and today I’m writing purely motivated by what I just finished reading.

Mindfire: Big Ideas for Curious Mind by Scott Berkun was such a pleasure to read and ended up igniting parts of my mind which I have to admit were becoming a bit numb that I felt the urge to take some time to first say thank you to the author and then recommend it to all your curious minds out there.

Now, go read it… it’s time well spent.

We Don’t Need No Regions

If your code reaches a level where you want to hide it behind regions then you have a problem that regions won’t solve. Regions are good to hide things that you don’t want to have knowledge about such as auto-generated code. Normally, when you’re developing you end up reading more code than you write it so why would you want to complicate the reading process.

I, for one, would love to have that one discussion around regions where someone convinces me that they solve a problem that has no other alternative solution, but I’m still waiting. The most frequent argument I hear about regions is that they allow you to structure your code, but why don’t just structure it using classes, methods and all that other stuff that OOP is about because at the end of the day, you should be doing object oriented programming and not region oriented programming.

Having said that, I do believe that sometimes is helpful to have a quick overview of a code file contents and Visual Studio allows you to do just that through the Collapse to Definitions command (CTRL + M, CTRL + O) which collapses the members of all types; if you like regions, you should try this, it is much more useful to read all the members of a type than all the regions inside a type.

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>

The 10 Commandments for Writing Code

  • Thou shalt not write code that you don’t know what it does;
  • Thou shalt not write unnecessary code.

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);
        }
    }
}

ASP.NET ViewState Tips and Tricks #1

In User Controls or Custom Controls DO NOT use ViewState to store non public properties.

Persisting non public properties in ViewState results in loss of functionality if the Page hosting the controls has ViewState disabled since it can no longer reset values of non public properties on page load.

Example:

public class ExampleControl : WebControl
{
    private const string PublicViewStateKey = "Example_Public";
    private const string NonPublicViewStateKey = "Example_NonPublic";

    // DO
    public int Public
    {
        get
        {
            object o = this.ViewState[PublicViewStateKey];

            if (o == null)
                return default(int);

            return (int)o;
        }
        set { this.ViewState[PublicViewStateKey] = value; }
    }

    // DO NOT
    private int NonPublic
    {
        get
        {
            object o = this.ViewState[NonPublicViewStateKey];

            if (o == null)
                return default(int);

            return (int)o;
        }
        set { this.ViewState[NonPublicViewStateKey] = value; }
    }
}

// Page with ViewState disabled
public partial class ExamplePage : Page
{
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        this.Example.Public = 10; // Restore Public value
        this.Example.NonPublic = 20; // Compile Error!
    }
}

Collection RemoveAll Extension Method

I had previously posted a RemoveAll extension method for the Dictionary<K,V> class, now it’s time to have one for the Collection<T> class.

The signature is the same as in the corresponding method already available in List<T> and the implementation relies on the RemoveAt method to perform the actual removal of each element.

Finally, here’s the code:

public static class CollectionExtensions
{
    /// <summary>
    /// Removes from the target collection all elements that match the specified predicate.
    /// </summary>
    /// <typeparam name="T">The type of elements in the target collection.</typeparam>
    /// <param name="collection">The target collection.</param>
    /// <param name="match">The predicate used to match elements.</param>
    /// <exception cref="ArgumentNullException">
    /// The target collection is a null reference.
    /// <br />-or-<br />
    /// The match predicate is a null reference.
    /// </exception>
    /// <returns>Returns the number of elements removed.</returns>
    public static int RemoveAll<T>(this Collection<T> collection, Predicate<T> match)
    {
        if (collection == null)
            throw new ArgumentNullException("collection");

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

        int count = 0;

        for (int i = collection.Count - 1; i >= 0; i--)
        {
            if (match(collection[i]))
            {
                collection.RemoveAt(i);
                count++;
            }
        }

        return count;
    }
}

Code Trivia #7

Lets go for another code trivia, it’s business as usual, you just need to find what’s wrong with the following code:

static void Main(string[] args)
{
    using (var file = new FileStream("test", FileMode.Create) { WriteTimeout = 1 })
    {
        file.WriteByte(0);
    }
}

TIP: There’s something very wrong with this specific code and there’s also another subtle problem that arises due to how the code is structured.


As explained in the comments, the using statement expands to the following code leading to the FileStream object never getting disposed because the finally is never executed.

FileStream file = new FileStream("test", FileMode.Create) { WriteTimeout = 1 };
try
{
    file.WriteByte(0);
}
finally
{
    if (file != null)
        ((IDisposable)file).Dispose();
}

With this in mind, one could be tempted to use a custom try/finally block for handling this situation. Something like this:

FileStream file = null;
try
{
    file = new FileStream("test", FileMode.Create)
    {
        WriteTimeout = 1
    };

    file.WriteByte(0);
}
finally
{
    if (file != null)
        file.Dispose();
}

However this suffers from the same problem but due to a different cause. Even though the constructor for the object is called inside the try clause the object initializer syntax prevents it from being assigned to the file variable before all properties have been initialized, leading to the file stream still not being disposed.

The expansion caused by the object initializer syntax is shown in the next sample of code:

FileStream file = null;
try
{
    FileStream compilerGenerated = new FileStream("test", FileMode.Create);

    compilerGenerated.WriteTimeout = 1;

    file = compilerGenerated;

    file.WriteByte(0);
}
finally
{
    if (file != null)
        file.Dispose();
}

Basically, you need to be careful with using blocks where the resource initialization expression may throw an exception and you also need to pay careful attention on the subtleties of using object initializer syntax.

Follow

Get every new post delivered to your Inbox.

Join 27 other followers