Feel like a geek and get yourself Ema Personal Wiki for Android and Windows

31 August 2009

Fixing the unit tests

In most of the cases, a failing unit test in my projects is a bug in the test and not a bug in the code it tests. It bring into question wether the unittests are worth the effort.

The answer is: YES. The unit tests are worth the effort. Once you created them:
  • You know how the code should be used: the unit test is your documentation
  • you will get a trigger if you change something for another usecase and break the code's original intent because the test will fail after that
  • The alternative is testing the code by starting the application itself, clicking to the right place, and testing the different scenario's. This is a very dull and time-consuming way of testing, and not very thorough. Creating a unit test for testing the code is way faster than the alternative, and the test will behave exactly the same each time you start it.

28 August 2009

Wrapping the NHibernate fetchmode

Configuring the NHibernate fetchmode and lazy/eager loading has two purposes: query efficiency (reduce database hits wherever possible) and preventing the dreaded LazyInitializationException. Most properties are configured for lazy loading, because this is a sensible default. This means you often have to tweak the fetchmode for particular queries in a particular way.

But combining queries and different fetchmodes scenario's will lead to a cartesian product of possibilities if used in a traditional, repository-like way.

For example:
  • IList<Author> GetAuthors()
  • IList<Author> GetAuthorsWithArticles()
  • IList<Author> GetAuthorsWithBooks()
  • IList<Author> GetAuthorsWithBooksAndArticles()
  • IList<Author> GetAuthorsByLastname(string lastname)
  • IList<Author> GetAuthorsByLastnameWithBooks(string lastname)
  • etc...

This looks like a bad design.

The solution is the Query Object pattern (here and here). This pattern wraps queries in objects.

If the query is an object, and the fetchmode can also be configured in an object-oriented way, applying fetchprofiles to a query and executing the query looks like this:
// .. get session and transaction somewhere ..

var results = 
  new AuthorsByNameQuery()
    .LastName("Adams")
    .WithBooks()
    .WithArticles()
      .List(session);

The query object wraps the criteria and fetchmode:
class AuthorsByNameQuery 
{
  internal DetachedCriteria Criteria;

  public AuthorsByNameQuery()
  {
    Criteria = DetachedCriteria.For<Author>();
  }

  public IList<Author> List(ISession session)
  {
    return Criteria
      .GetExecutableCriteria(session)
      .List<Author>();
  }

  public AuthorsByNameQuery Lastname(string lastname)
  {
    Criteria.Add(Expression.Eq("Lastname", lastname));
    return this;
  }

  public AuthorsByNameQuery WithBooks()
  {
    Criteria.SetFetchMode("Books", FetchMode.Select);
    return this;
  }
  public AuthorsByNameQuery WithArticles()
  {
    Criteria.SetFetchMode("Articles", FetchMode.Select);
    return this;
  }
}

I have been using queries and fetchprofiles this way in a few projects now and it really helps to structure the possibilities.

23 August 2009

Chaining ASP.NET MVC actions

Action Chaining is using the output of action A as input for action B. Applying this pattern to ASP.NET MVC projects is not trivial. This post is meant as a quick start.

Suppose you have the following scenario
  • client places order in browser

  • system redirects client to ~/Order/ThankYou

  • system sends email to client with summary about order

  • system shows summary of order to client
To accomplish this, it would be convenient to reuse ~/Order/Summary for both the email and the browser page


There are other usecases in which Action Chaining would be a valid pattern, for example in cases where you want to show the output of one action as PDF or as HTML depending on the required format. Apache Cocoon is based on this pattern.

The way to execute an action and capture the output in ASP.NET MVC involves some hijacking of the Response Stream and the RouteValues.

The Response Stream can messed with using a ResponseFilter. A response filter is a class that inherits from stream and takes a stream as constructor argument. The stream in the constructor is the original Response stream (or another filter, they can be chained). If you set the filter, the filter stream gets the writes and is supposed to pass the writes to the wrapped stream. Which is exactly what we won't do: we jealously keep the bytes to ourselves in a memorystream:
class BufferingMemoryStreamFilter : MemoryStream
{
public BufferingMemoryStreamFilter(Stream wrappedStream)
{
// ignore the wrapped stream
}
}
Controllers react on the routevalues to find the right action and view. Because we will be executing another action (perhaps on another controller also), the routevalues should be changed for the occasion and restored afterwards.

The method that execute and capture an arbitrary action on an arbitrary controller is posted below.
string GetActionOutput(string controller, string action)
{
// hijack the response stream
var orgResponseFilter = HttpContext.Response.Filter;
var memoryStreamFilter = new BufferingMemoryStreamFilter(
HttpContext.Response.Filter);
HttpContext.Response.Filter = memoryStreamFilter;

// hijack routeData
var routeData = ControllerContext.RequestContext.RouteData;
var orgAction = routeData.Values["action"];
var orgController = routeData.Values["controller"];
routeData.Values["action"] = action;
routeData.Values["controller"] = controller;

var c = ControllerBuilder.Current
.GetControllerFactory()
.CreateController(ControllerContext.RequestContext, controller);
c.Execute(ControllerContext.RequestContext);

HttpContext.Response.Flush();
memoryStreamFilter.Position = 0;
string result;
using (var r = new StreamReader(memoryStreamFilter))
result = r.ReadToEnd();

// restore
HttpContext.Response.Filter = orgResponseFilter;
routeData.Values["action"] = orgAction;
routeData.Values["controller"] = orgController;

return result;
}
Include this in a (base) controller or in a class that has access to the controller to be able to use it.

The code in this post is licensed under the Apache 2.0 license, which in practice means you have permission to use it.

14 August 2009

Peeking into the ASP.NET MVC source with the debugger

Peeking into sourcecode of open source projects can be very useful: you can learn from it, understand the framework you're using better, and find hidden features and maybe you can contribute to the project.

It can be very insightful to be able to step into the code with a debugger. For future reference, this is how to do it for ASP.NET MVC.

Download the source with svn from https://aspnet.svn.codeplex.com/svn/MVC.


Open the solution MvcDev.sln and check that it builds (just to know for sure).

Add a new ASP.NET MVC website to the solution and set it as startup project (it will be bold)


From the new MvcApplication, remove the reference to System.Web.Mvc


Now add a project reference to the System.Web.Mvc project.


Because the System.Web.Mvc assembly doesn't have a strong key, you have to change the references to the System.Web.Mvc assembly to exclude version info and public key token. In the TWO web.config files (one in the root of the web app, one in the Views folder) remove the Version, Culture and PublicKeyToken information from all references to the System.Web.Mvc entries. For example
<add assembly="System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />

will become
<add assembly="System.Web.Mvc" namespace="System.Web.Mvc" tagPrefix="mvc" />



Now you can set breakpoints, hit F5 and start peeking around.

10 August 2009

IE, ASP.NET MVC, AJAX and browser caching

IE caches AJAX requests and won't reload the resource by default. Other browsers do it differently. I am not sure who's "right" here (this document may have the answer). But this can be very annoying behaviour in AJAX applications.

The solution is to explicitely tell IE not to cache.

On this website kazimanzurrashid posted an ActionFilterAttribute to control browser caching behaviour. I changed it a bit so it is possible to prevent any browser caching.

I now have an attribute on my base controller class:
[BrowserCache(PreventBrowserCaching=true)]

This prevents any caching by default. This can be overriden if required (which I never do).

The attribute looks like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace YourNameSpaceHere
public class BrowserCacheAttribute : ActionFilterAttribute
{
///
/// Gets or sets the cache duration in seconds.
/// The default is 10 seconds.
///

/// The cache duration in seconds.
public int Duration
{
get;
set;
}

public bool PreventBrowserCaching
{
get;
set;
}

public BrowserCacheAttribute()
{
Duration = 10;
}

public override void OnActionExecuted(
ActionExecutedContext filterContext)
{
if (Duration < 0) return;

HttpCachePolicyBase cache = filterContext.HttpContext
.Response.Cache;

if (PreventBrowserCaching)
{
cache.SetCacheability(HttpCacheability.NoCache);
Duration = 0;
}
else
{
cache.SetCacheability(HttpCacheability.Public);
}

TimeSpan cacheDuration = TimeSpan.FromSeconds(Duration);
cache.SetExpires(DateTime.Now.Add(cacheDuration));
cache.SetMaxAge(cacheDuration);
cache.AppendCacheExtension("must-revalidate,"
+ "proxy-revalidate");
}
}
}