Thursday, 13 November 2008
During my recent exploration of the Microsoft ASP.NET MVC framework I hit a roadblock when posting data back from the browser using a form. The scenario involved was as basic as you could imagine, a simple HTML form posting back an Id to a controller:
public class JobController : Controller
{
public IJobService JobService { get; set; }
public ActionResult Load(int id)
{
ViewData["Job"] = JobService.Load(id);
return RedirectToAction("ViewJob");
}
}
The issue I was having was that my controller wasn’t picking up the Id value. Changing the code to use the request object solved the problem:
public class JobController : Controller
{
public IJobService JobService { get; set; }
public ActionResult Load()
{
var id = int.Parse(Request.Form["id"]);
ViewData["Job"] = JobService.Load(id);
return RedirectToAction("ViewJob");
}
}
However, this solution was far from satisfactory. By chance I stumbled across a blog post that was explaining the same issue, caused by the default routing taking precedence over request values. Removing the Id from the rule solved the problem.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}", // URL with parameters
new { controller = "Home", action = "Index" } // Parameter defaults
);
}
Or not. Now the code worked perfectly for the first request, however when the value was changed on subsequent requests, the original value was still retained by the controller. After much searching, I finally found the solution on Stack Overflow. I needed to configure my IoC container (Windsor) to use a transient lifestyle, as the controller wasn’t being destroyed between requests.
${JobService}
This is how the Monorail controller facility in Windsor behaves be default out of the box; I could quite fathom why the MVC Contrib integration would not do so as well. One to chalk up to experience...
Labels: ASP.NET, MVC, Windsor
Thursday, 6 November 2008
I’ve recently started to use the Microsoft ASP.NET MVC framework. Being very familiar with the Castle Monorail, I was a bit dubious to how the Microsoft framework would hold up.
One of the first tasks I had difficulty with was writing a basic unit test to see whether a user was logged in, through holding their credentials in session:
using NUnit.Framework;
[TestFixture]
public class HomeControllerTest
{
private HomeController controller;
[Test]
public void TestIndexAction()
{
controller = new HomeController();
// Display the homepage
controller.Index();
// Verify the user object hasn't been set in session
Assert.IsNull(controller.ControllerContext.HttpContext.Session["user"]);
}
}
When I can to run this test, it failed as the HttpContextSessionBase class hadn’t been instantiated. After googling this, several blogs had described the same issue; however I couldn’t find an answer without manually Mocking or creating Fakes. Monorail conversely, has the solution is built into the framework:
[TestFixture]
class HomeControllerTest : BaseControllerTest
{
private HomeController controller;
[SetUp]
public void SetUp()
{
controller = new HomeController();
PrepareController(controller);
}
[Test]
public void TestIndexAction()
{
// Display homepage
controller.Index();
// Verify the user object hasn't been set in session
Assert.IsNull(controller.Context.Session["user"]);
}
}
After further research, I came across the MVC Contrib Project on Codeplex. Adding references to their testing assembly I was able to write the following:
using MvcContrib.TestHelper;
using NUnit.Framework;
[TestFixture]
public class HomeControllerTest
{
private HomeController controller;
private TestControllerBuilder builder;
[SetUp]
public void SetUp()
{
builder = new TestControllerBuilder();
controller = new HomeController();
builder.InitializeController(controller);
}
[Test]
public void TestIndexAction()
{
// Display the homepage
controller.Index();
// Verify the user object hasn't been set in session
Assert.IsNull(controller.ControllerContext.HttpContext.Session["user"]);
}
}
In order to run it requires a reference to Rhino.Mocks, so I guess under the hood this is what it's using.
It would be good if this kind of testing simplicity was baked into the framework, as in Monorail, but it seems ASP.NET MVC still has some way to go to escape the burden of the sealed ASP.NET HttpContext classes.
Labels: ASP.NET, MVC, Testing
I’ve recently been investigating using virtual machines for testing and deploying environments using the free VMware Server 2.0. Whilst all went remarkably smoothly, one problem that had me stumped for a few hours was working out how to get the guest machines to automatically start when the host was rebooted. Google didn’t provide a solution, but eventually I found this:
Click on the “Host” machine in the inventory tab:
An “Edit Virtual Machine Startup/Shutdown Settings” menu item should appear on the right:

You can then move the machines up and down to enable automatic startup... simple! (If you know how)

Labels: VMware