Archive for the ‘Architecture’ Category.

When the Overlords Demand WebForms You Can Still Do MVC

I have worked for several clients that seem reluctant to use ASP.NET MVC for whatever reason. I’m sure you can imagine all of them and come up with counter-arguments…I know I have. If I am forced to use WebForms I have a simple MVC pattern that I like to use that allows me to write testable code (always my main concern). The following code should be considered a start point. I have used it on two projects, but I have had to make additions to suit each. I am only showing you enough to demonstrate how everything is hooked together.

Note: IContainer (not listed) represents an IoC container. In my case, I am implementing it with Unity.

The View

public interface IView
{
    IList<string> Errors { get; set; }
    void RedirectToRoute(string route, object routeParameters);
}

public abstract class PageBase<T> : Page where T : ControllerBase
{
    protected T Controller { get; private set; }
    protected IContainer Container { get; private set; }

    protected PageBase()
    {

    }

    public void RedirectToRoute(string route, object routeParameters)
    {
        Response.RedirectToRoute(route, routeParameters);
    }

    protected abstract bool NeedToAuthenticate();
    protected abstract void Authenticate();

    protected override void OnLoad(EventArgs e)
    {
        if (NeedToAuthenticate())
        {
            Authenticate();
            return;
        }

        Container = Application.GetContainer();
        Controller = Container.Resolve<T>();

        if (Controller == null)
        {
            throw new Exception("Could not resolve controller for " + typeof(T));
        }

        Controller.PageData = (Page.RouteData != null) ? Page.RouteData.Values : new RouteValueDictionary();

        Controller.SetView(this);

        if (IsPostBack)
        {
            Controller.PostBack();
        }
        else
        {
            Controller.Load();
        }

        Controller.SubscribeToEvents();

        base.OnLoad(e);

    }

}

The Controller

public abstract class ControllerBase<TView> : ControllerBase where TView : IView
{
    public TView View { get; set; }

    public override void SetView(object view)
    {
        View = (TView)view;
    }
}

public abstract class ControllerBase : IPageController
{
    public IDictionary<string, object> PageData { get; set; }

    protected ControllerBase()
    {
        PageData = new Dictionary<string, object>();
    }

    public object this[string key]
    {
        get
        {
            if (PageData != null && PageData.ContainsKey(key))
            {
                return PageData[key];
            }

            return null;
        }
    }

    /// <summary>
    /// Called during initial request.
    /// </summary>
    public virtual void Load()
    {
        // See PageBase
    }

    /// <summary>
    /// Called during a postback
    /// </summary>
    public virtual void PostBack()
    {
        // See PageBase
    }

    public virtual void SetView(object view)
    {
        // See PageBase
    }

    public virtual void SubscribeToEvents()
    {
        // See PageBase
    }
}

The Model

Not shown. The model will be a data type that corresponds to the UI. Typically, the View interface will contain a Model property that allows the Controller to get/set this information.

Hooking it up

What makes it happen is the following line of code (in PageBase.cs):

Controller = Container.Resolve<T>();

This allows the Controller to be created via IoC which allows you to inject dependencies through the constructor.

This is basically all there is to it, but I think an example might be in order. So, say I need a page that allows an admin to view system errors, I will create the following 4 files:

  • SystemErrorsView.aspx (WebForm)
  • ISystemErrorsView.cs (View interface)
  • SystemErrorsController.cs (the Controller)
  • SystemErrorsModel.cs (optional, may not be needed)
public interface ISystemErrorsView : IView
{
    void SetSystemErrors(IList<string> systemErrors);
}

public partial class SystemErrorsView : PageBase<SystemErrorsController>, ISystemErrorsView
{
    public void SetSystemErrors(IList<string> systemErrors)
    {
        // display the errors somehow
    }
}

public class SystemErrorsController : ControllerBase<ISystemErrorsView>
{
    public SystemErrorsController(/* inject stuff here using IoC */)
    {
        // injected members
    }

    public override void Load()
    {
        // use stuff that you injected to get data for the view
        var systemErrors = ...
        View.SetSystemErrors(systemErrors);
    }

    public override void SubscribeToEvents()
    {
        // see below
    }

}

Events

As you can see from above, Controller-to-View communication occurs directly through the ISystemErrorsView interface. View-to-Controller communication happens using events.

Let’s continue the example. We will add a Clear button to the View that allows an admin to clear all system errors.

The first thing we do is add an event to the View interface:

public interface ISystemErrorsView : IView
{
    event EventHandler WhenCleared;
    void SetSystemErrors(IList<string> systemErrors);
}

Now, we need to implement this in the code-behind for the View. Assume we have a button on the page called btnClear. We are going to intercept the buttons click event and then raise the WhenCleared event that we defined on the View interface:

public partial class SystemErrorsView : PageBase<SystemErrorsController>, ISystemErrorsView
{
    public event EventHandler WhenCleared;

    private void btnClear_Clicked(object sender, EventArgs e)
    {
        if (WhenCleared != null)
        {
            WhenCleared(sender, e);
        }
    }
}

Lastly, we need to subscribe to the event in our Controller:

public class SystemErrorsController : ControllerBase<ISystemErrorsView>
{
    public override void SubscribeToEvents()
    {
        View.WhenCleared += WhenCleared;
    }

    public void WhenCleared(object sender, EventArgs e)
    {
         // update database
         // refresh view
    }

}

Conclusion

I don’t like writing conclusions. That’s all I have. All typical warnings and caveats apply.

Windows Azure and Object-Oriented Testable Code

I am currently working on an Azure application that makes heavy use of blob storage (think raw data storage), table storage (think object database) and queues (think queues). From a high level point of view, these are constructs that could be useful to many enterprise applications being built today.

With that said, I’ve had to do a little work to make Azure more friendly to my way of building software. Let me deviate for a moment…

Lately, I have tried to distill everything that I know about object-oriented programming down to one statement: If I can test it, it’s good enough for now. There’s code readability and things like that which must be considered, but when I say this I am really referring to the structural elements of the application. Good enough for now means that everything is in a state that can be easily refactored later (if need be) and it means that the code is testable in an automated way (NUnit). My designs tend to rely on dependency injection, inversion of control and make heavy use of abstractions.

The Azure Storage API (what I’m mostly familiar with in the world of Azure) seems to be a throwback to older MS designs: sealed classes based on no abstractions (interfaces, abstract base classes). In other words, it’s an all or nothing black box approach. So forget about mocking. Granted, MS makes stuff easy to use but at the same time doesn’t seem to understand that that how I connect everything together is important, too.

Fortunately, it has been trivial to get around this using Bridge/Adapter-ish patterns.

My approach to blob storage has been something along these lines (THIS IS NOT PRODUCTION READY CODE – EXAMPLE ONLY):

public interface IBlob
{
    void UploadFile(string fileName);
    // just a few more methods here
    // not exposing every method on CloudBlob
}

public interface IBlobContainer
{
    IBlob GetBlobReference(string blobAddress);
}

public interface IBlobStorage
{
    IBlobContainer GetContainer(string name);
}

public class BlobStorage : IBlobStorage
{
    private readonly CloudBlobClient _client;

    public BlobStorage()
    {
        var account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
        _client = account.CreateCloudBlobClient();
    }

    public IBlobContainer GetContainer(string name)
    {
        return new BlobContainer(_client, name);
    }
}

public class BlobContainer : IBlobContainer
{
    private readonly CloudBlobClient _client;
    private readonly string _containerName;

    public BlobContainer(CloudBlobClient client, string containerName)
    {
        _client = client;
        _containerName = containerName;
    }

    public IBlob GetBlobReference(string blobAddress)
    {
        var container = _client.GetContainerReference(_containerName);
        container.CreateIfNotExist();
        var blob = container.GetBlobReference(blobAddress);
        return new Blob(blob);
    }
}

public class Blob : IBlob
{
    private readonly CloudBlob _cloudBlob;

    public Blob(CloudBlob cloudBlob)
    {
        _cloudBlob = cloudBlob;
    }

    public void UploadFile(string fileName)
    {
        _cloudBlob.UploadFile(fileName);
    }
}

This gives me IBlob, IBlobContainer and IBlobStorage….my own interfaces, which can easily be mocked and improves my testability.

I am doing something similar with queues. Again, this is an example only (I say this over and over in an attempt to keep “nitpicking” type comments to a minimum). Rest assured, my production code is a little more rich than this.

public interface IQueueMessage
{
    object Content { get; }
    string AsString { get; }
}

public interface IQueue
{
    void AddMessage(IQueueMessage message);
    IQueueMessage GetMessage();
    void DeleteMessage(IQueueMessage message);
}

public interface IQueueLocator
{
    IQueue GetQueue(string queueName);
}

public class QueueMessage : IQueueMessage
{
    internal CloudQueueMessage CloudQueueMessage { get; private set; }

    public QueueMessage(CloudQueueMessage cloudQueueMessage)
    {
        CloudQueueMessage = cloudQueueMessage;
    }

    public QueueMessage(byte[] content)
    {
        CloudQueueMessage = new CloudQueueMessage(content);
    }

    public QueueMessage(string content)
    {
        CloudQueueMessage = new CloudQueueMessage(content);
    }

    public object Content
    {
        get { return CloudQueueMessage; }
    }

    public string AsString
    {
        get { return CloudQueueMessage.AsString; }
    }
}

public class Queue : IQueue
{
    private readonly CloudQueue _cloudQueue;

    public Queue(CloudQueue cloudQueue)
    {
        _cloudQueue = cloudQueue;
    }

    public void AddMessage(IQueueMessage message)
    {
        if (_cloudQueue == null)
            return;
        _cloudQueue.AddMessage((CloudQueueMessage)message.Content);
    }

    public IQueueMessage GetMessage()
    {
        if (_cloudQueue != null)
        {
            var content = _cloudQueue.GetMessage();
            return new QueueMessage(content);
        }

        return null;
    }

    public void DeleteMessage(IQueueMessage message)
    {
        if (_cloudQueue != null)
        {
            var content = (CloudQueueMessage)message.Content;
            _cloudQueue.DeleteMessage(content);
        }
    }
}

public class QueueLocator : IQueueLocator
{
    private static CloudQueueClient _queueStorage;

    public IQueue GetQueue(string queueName)
    {
        if (_queueStorage == null)
        {
            CreateQueueStorage();
        }

        if (_queueStorage != null)
        {
            var cloudQueue = _queueStorage.GetQueueReference(queueName);
            cloudQueue.CreateIfNotExist();
            return new Queue(cloudQueue);
        }

        return null;
    }

    private static void CreateQueueStorage()
    {
        var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
        _queueStorage = storageAccount.CreateCloudQueueClient();
    }
}

Conclusion

Not perfect, I know, but it’s good enough for now. I have hidden the fact that there are CloudStorageAccount’s and CloudBlobClient’s and CloudQueueClient’s. This may or may not work for you. My main concern is that I have something that I can mock. I can use dependency injection and inversion of control and I am able to see how my application interacts with Azure in my unit tests.

Domain Oriented NLayered .NET 4.0 Architecture Guide

MSDN Architecture Spain just released Domain Driven Design in .NET 4.0 guide. I haven’t had a chance to read it but it’s in my queue.