Tuesday, September 20, 2011

Beware the smart quotes when writing code outside a code editor!

I struggled a few hours today performing a REST query from the IE address bar. I copied the URL from some source to One Note, and changed it a bit. I pasted it back into IE, and just couldn't get it to work.

Eventually, after much pain and suffering, I typed a single quote next to the existing one in notepad to try escaping some text, and noticed a subtle difference between the quotes. See if you can spot it:  ‘ ’ '   While these three characters look similar to you and me, they are in fact very different to text parsers.

My guess is that at some point it must have been inserted by the auto correct feature of a helpful Microsoft Office application. A little further digging exposed that there is a way to turn off the "insert smart quotes" feature in Office applications, explained here.

There are more info available about smart quotes here. A particularly handy tip, is that you can undo the smart quote conversion by pressing ctrl-z immediately after typing the quote character.

Sunday, September 18, 2011

How to Render a partial view in the controller.

I had the need today to render some html using a partial view, and then add that html to a JSON Result in MVC 3. I found a few examples on the internet that does it by extending the Controller class, but I don't particularly like this approach as it seemed hard to test. The reason is that it requires the view to be resolved in the controller itself, using built-in methods that rely on other static methods ("dirty, evil!"). I'm sure you can make it work by mocking some of the funkiness around view engines, but that just seemed like too much hard work.

My solution is to apply a bit of dependency injection by injecting a new class called a PartialViewRenderer as an interface into my controller. This class will abstract the rendering away, thereby removing the dependency on the view engines etc. from the controller. My controller now becomes easily testable again! This also adheres to the default approach of rendering views etc outside of the controller. You can also test the rendering seperately, but I haven't bothered with that.

The code for the renderer is as follows:

public class PartialViewRenderer : IPartialViewRenderer
{
    public string RenderOutput(ControllerContext controllerContext, object model, string partialViewName)
    {
        using (StringWriter writer = new StringWriter())
        {
            ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controllerContext, partialViewName);
            ViewContext viewContext = new ViewContext(controllerContext, viewResult.View, new ViewDataDictionary(model), 
                controllerContext.Controller.TempData, writer);
            viewResult.View.Render(viewContext, writer);
            return writer.GetStringBuilder().ToString();
        }
    }
}

It is used in the following action:

public JsonResult LoadUrl(string request)
{
    RestUrlRequest data = new JavaScriptSerializer().Deserialize(request);
    RestSampleUrlModel model = restExamplesProvider.LoadUrl(data);
    model.OutputHtml = outputRenderer.RenderOutput(ControllerContext, model, formatToOuputViewMap[data.Format]);
    return Json(model, JsonRequestBehavior.AllowGet);
}

outputRenderer is an instance of the PartialViewRenderer that we've injected in this controllers' constructor.

A test can be done as such:

[TestMethod]
public void LoadUrlReturnsUrlResultWithOuputFromRendererForFormat()
{
    RestSampleUrlModel model = new RestSampleUrlModelFixture().Build();
    IRestExamplesProvider samplesProvider = new RestExamplesProviderMockFixture { RestSampleUrlModel = model }.Build();
    RestBrowserControllerFixture controllerFixture = new RestBrowserControllerFixture { RestSamplesProvider = samplesProvider };
    RestBrowserController controller = controllerFixture.Build();
    RestUrlRequest request = new RestUrlRequestFixture { Format = "atom" }.Build();

    JsonResult result = controller.LoadUrl(new JavaScriptSerializer().Serialize(request));

    result.Should().NotBeNull();
    RestSampleUrlModel data = (RestSampleUrlModel) result.Data;
    data.OutputHtml.Should().Be("mock render output");
    controllerFixture.RestOutputRenderer.AssertWasCalled(mock => mock.RenderOutput(controller.ControllerContext, model, "atom"));
}


I used a mock for the implementation of the OutputRenderer in this test. The mock itself is setup in a seperate fixture class. The renderer class itself can be extended to be more flexible with different overloads for the method, but that is surplus to my requirements.