There has a been a lot of talking on a possible “big design flaw” in ASP.NET MVC: partial view path resolution was not cached and so a big performance issue. It all started with Rudi Benkovic’s presentation on ASP.NET MVC performances.

I also wrote a commentary on his presentation, but I was a bit skeptical about the fact that view path resolution was faster with a full url than with just the name of the view. I said:

This last one looks strange to me because the RenderPartial method should be caching the path resolution: maybe it’s a bug, or the test was performed with a pre-release version that didn’t cache the result.

But I didn’t have time to really test the behavior.

Then today another post came out: ASP.NET MVC: Hidden Performance Problem with HtmlHelper.RenderPartial functions.

He says that for each view rendered, all the search path are probed and, in order to understand whether a file exists or not, they throw an exception. This sounds silly to me, so this evening I decided to try it myself.

And I found the way to improve the performances without adding another layer of cache as someone was already planning to. Just don’t run in debug mode:

<compilation debug="false">

Yes, it’s that simple.

Since ASP.NET MVC source code is public (actually it’s OpenSource) I had a look at it. And I found out the following line:

protected VirtualPathProviderViewEngine() {
    if (HttpContext.Current == null || HttpContext.Current.IsDebuggingEnabled) {
        ViewLocationCache = DefaultViewLocationCache.Null;
    }
    else {
        ViewLocationCache = new DefaultViewLocationCache();
    }
}

This says: if you are in debug mode (or are not in a web environment, like in tests), don’t cache. Otherwise use the cache.

I also went a bit on, and added some logging inside the view path resolution, in order to run it in release mode and see with my eyes that the cache was being used. The code that follows is the GetPath method inside the VirtualPathProviderViewEngine.cs file (code truncated to enhance readability):

private string GetPath( /* truncated */) {

     /* truncated */

      if (useCache) {
        string result = ViewLocationCache.GetViewLocation(
                                          controllerContext.HttpContext, cacheKey);
        if (result != null) {
            controllerContext.HttpContext.Response.Write(
                      String.Format("{0} lookup returned {1}\r\n", name, result));
            return result;
        }
    }

    controllerContext.HttpContext.Response.Write(
                String.Format("{0} lookup no cache\r\n", name));
    return (nameRepresentsPath) ?
        GetPathFromSpecificName(/* truncated */) :
        GetPathFromGeneralName(/* truncated */);
}

If you run in debug mode you will always see, when calling the RenderPartial on the LogOnUserControl, “LogOnUserControl lookup no cache”. But if you run it in release mode, you will get the no cache message the first time you run it, and later you’ll get “LogOnUserControl lookup returned ~/Views/Shared/LogOnUserControl.ascx”.

So, problem solved, no “big error” inside ASP.NET MVC 1.0, just someone that forgot the set the debug flag to false when doing its performance testing. And innocently spread the panic around that.

Actually finding that they decided to use no cache in debug mode was difficult to discover without looking at the code, but when you do tests, especially performance test, remember to run in release mode.

There are also other reasons why you don’t want to run production or performance testing code in debug mode. Read what Tess has to say about that: ASP.NET Memory: If your application is in production… then why is debug=true

kick it on DotNetKicks.com

Technorati Tags: ,