MVC Html.Resolve() – Resolve URLs to your page

For the current MVC application I’m developing, I needed to host the site under a IIS Virtual Directory.  This caused a problem as I can’t use the following code:

<%=Html.Image("~/Content/icon_green.gif") %>

This would ignore the fact that I was under a Virtual Directory and point to the root site – http://mysite/ instead of http://mysite/myvirtual/ like I want.

Rob Conery mentioned a Html.ResolveUrl method, however I couldn’t find the method on the HtmlHelper so I wrote my own.  The method is called Resolve and is an extension to the HtmlHelper within MVC. Here is one of the unit tests for it.

public void Resolve_With_IIS_Virtual_Directory_Returns_Full_Path()
    HtmlHelper html = CreateHtmlHelper(“

    string result = html.Resolve(“~/Content/t.jpg”);
http://localhost/TestProject/Content/t.jpg”, result);

Implementation is very simple, we prefix the virtual directory with the application path if required.

public static string Resolve(this HtmlHelper helper, string virtualUrl)
    if (!virtualUrl.StartsWith(“~/”))
        return virtualUrl;

    virtualUrl = virtualUrl.Remove(0, 2);

    string applicationPath = helper.ViewContext.HttpContext.Request.ApplicationPath;
    if(string.IsNullOrEmpty(applicationPath) || !applicationPath.EndsWith(“/”))
        applicationPath = applicationPath  + “/”;

    return applicationPath + virtualUrl;

However, this brought up an interesting point. How do you test extension methods? It turns out, you can easily test the methods, you just need to create the object they are extending and call the method – obviously.

The problem with this is, HtmlHelper (the object I’m extending) has a number of dependencies, for example in my Resolve method I’m calling HttpContext in order to get the ApplicationPath.

In order to create the HtmlHelper object, I added myself a little helper method. I’m using Rhino Mocks 3.5 in order to generate the stubs, sadly ViewContext requires a number of different parameters (the only one I care about is httpContext), as a result I had to generate a number of different stubs.

private HtmlHelper CreateHtmlHelper(string appPath)
    HttpContextBase httpContext = MockRepository.GenerateStub();
    HttpRequestBase httpRequestBase = MockRepository.GenerateStub();
    httpRequestBase.Stub(h => h.ApplicationPath).Return(appPath);
    httpContext.Stub(h => h.Request).Return(httpRequestBase);

    ViewContext viewContext = MockRepository.GenerateStub(httpContext,
                                                                    new RouteData(),
                                                                    “Test”, “MasterTest”, new ViewDataDictionary(),
                                                                    new TempDataDictionary(httpContext));

    return new HtmlHelper(viewContext, MockRepository.GenerateStub());

The end result is that I have my HtmlHelper object created which returns a known ApplicationPath, this allows me to fully test my extension method. However, I have had put in some additional effort due to requiring ViewContext.

Download Tests: HtmlExtensionTests.txt
Download Implementation: Html.txt

Technorati Tags:

SubSonic and MVC

So from my last few posts, you might know I’m a fan of SubSonic and Rob Conery (SubSonic creator) has accepted an offer to join Microsoft.  His role, working on the the MVC framework and SubSonic full time.

The team seriously have some amazing people working for them and on this MVC framework, what an amazing team that would be to work in!!

“SubSonic will be the convention-driven toolset for Microsoft’s new MVC framework”  SubSonic will remain open source, but from the sounds of it, SubSonic will be the ORM for MVC. 

Jon Galloway always said “Microsoft should ship SubSonic…” I think they have just gone one better by employing the creator and leaving it open source!! How cool!

I can’t wait for the first drop of the framework, going to take a lot of my attention I think.  It’s going to rock!!

Technorati Tags: ,