Thursday, August 11, 2011

ASP.NET dependency injection using Unity Application Block


ASP.NET was not designed with the concepts of DI and IoC in mind. That makes it very difficult to actually configure a website/ application using ASP.NET to use the concepts of IoC and resolve the dependencies when the pages are requested. An easier way to resolve the dependencies on the page will be using the container and requesting for the resolved types for dependencies. A much better approach is to interpret the page creation implementation code in ASP.NET and resolve the dependencies on the Page from there. In this post I'll show a sample scenario where we'll intercept the page creation logic and resolve the dependencies on the page using Unity container.
The sample used in this article has views that have dependencies on the respective presenters. The presenters will depend on the service abstractions to do their work.
I have the base presenter and view interface declarations as
public abstract  class AppPresenter where T : IAppView
{
    public T View
    {
        get
        {
            if (HttpContext.Current == null) return DependencyInjection.Container.Resolve();
            return (T)HttpContext.Current.Handler;
        }
    }

    public abstract void InitializeViewEvents();
}

public interface IAppView
{
}

For resolving the dependencies on my views, I have created a custom PageHandler implementation which looks like.
public class UnityPageHandlerFactory : PageHandlerFactory
{
    public override IHttpHandler GetHandler(HttpContext context, string requestType, string virtualPath, string path)
    {
        var view = base.GetHandler(context, requestType, virtualPath, path) as Page;
        if (view == null) return view;

        DependencyInjection.Container.BuildUp(view.GetType(), view);
        return view;
    }
}

<httpHandlers>
  <add path="*.aspx" verb="*" type="BlogsPrajeesh.WebForms.DI.UnityPageHandlerFactory" />
httpHandlers>
I have created an extension method on the container to register the dependencies while initializing the container
public static class DependencyRegistrations
{
    public static void SetupRegistrations(this UnityContainer container)
    {
        container
            .RegisterType<IHomeView, HomeViewNullObject>()
            .RegisterType<IHomeService, HomeService>()
            .RegisterType<HomePresenter>();
    }
}

Later when the container is initialized you can call the SetupRegistrations methods on the container. container.SetupRegistrations();

A sample view – Presenter implementation can be done like.
public partial class Home : Page, IHomeView
{
    private HomePresenter _presenter;
    public new event EventHandler OnLoad;

    [Dependency]
    public HomePresenter Presenter
    {
        set { _presenter = value; }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        _presenter.InitializeViewEvents();
        if (OnLoad != null) OnLoad(this, EventArgs.Empty);
        lblHello.Text = _presenter.GetMessage();
    }
}

public class HomePresenter : AppPresenter<IHomeView>
{
    private readonly IHomeService _homeService;

    public HomePresenter([Dependency] IHomeService homeService)
    {
        _homeService = homeService;
    }

    public string GetMessage()
    {
        return _homeService.GetMessage();
    }

    public override void InitializeViewEvents()
    {
        View.OnLoad += new EventHandler(View_OnLoad);
    }
}

Using this kind of an implementation allows you to completely unit test your ASP.NET web application.
[TestMethod]
public void GetMessageShouldRetrieveTheMessageFromTheRegisteredService()
{
    var presenter = DependencyInjection.Container.Resolve<HomePresenter>();
    Assert.IsFalse(string.IsNullOrEmpty(presenter.GetMessage()));
}

No comments: