The problem that has been discovered in this blog entry was resolved – thanks to Simone. Read my follow up blog post that describes why I ran into this problem: /blog/2009/04/23/aspnet-mvc-htmlhelperrenderpartial-caches-resolved-names-in-release-mode/
There are some great blog entries about how to improve ASP.NET MVC Performance. Simone Chiaretta bloged about How to improve the performance of ASP.NET MVC web applications. One of his thoughts were on HtmlHelper.RenderPartial and that it can have a significant performance impact on your application. I ran across the same problem and I figured out why that is!
What is HtmlHelper.RenderPartial?
System.Web.Mvc.Html.RenderPartialExtension.RenderPartial extends the HtmlHelper class by offering the ability to render a partial view into your ASP.NET Web Page. The first string parameter allows you to provide a partial view name. This can be the name of an aspx or aspc file. The file can be in the same directory as the ASP.NET Page that calls RenderPartial or it can be in the Shared subdirectory. RenderPartial will make sure to find the correct view to render. Here is an example how it looks in the markup code:
What happens when a normal ASP.NET MVC Page is processed?
I am currently working with the project Kigg from CodePlex. Its a great application that makes extensive use of ASP.NET MVC. When browsing to the default page several things happen. ASP.NET processes the default page. The application uses a master page which also gets processed. Both – the master page and the default page contain calls to the HtmlHelper class to render certain controls like Menu, SearchBox, MembershipBox and more. Kigg uses RenderPartial by passing a partial name as first parameter. From the outside everything looks fine and it works great. You might be surprised to see the following view captured with Dynatrace:
When we drill into the PurePath we see that those exception are thrown by RenderPartial:
Why do we see this problem?
When passing a partial view name to the RenderPartial method – RenderPartial needs to resolve the partial view name to a physical file that will be loaded and rendered. In order to do this – the ViewEngine is used to resolve the name. The default ViewEngine for ASP.NET MVC Applications is System.Web.Mvc.WebFormViewEngine. In the constructor of this engine we can see the individual file patterns that are used to locate the partial view.
This location patterns are used in case a partial name is passed to the RenderPartial method. For every pattern – RenderPartial is calling a File.Exists to check the files existance – and throwing an exception in case the file does not exist. In the case of the PurePath shown above – the actual control that was referenced was stored in the ~/Views/Shared directory and had an .ascx extension. The first 3 attempts to locate the file with the other file patterns failed. The 4th succeeded and the control could be loaded.
The problem that we have though is that every page request is throwing many exceptions. Exceptions that are hidden for us developers and that don’t actually show a real problem with the application. But – the more exceptions that are thrown the more overhead you have. Imagine several hundred concurrent users on this front page. Every web request throws 16 exception (in this case) – making it several thousand exceptions every second if we expect some decent load. Exceptions – that cause overhead and degrade overall performance.
How can we solve it?
The easiest way to solve this is by providing the full name to the control that should be rendered. Instead of using
we can use
Frameworks like ASP.NET MVC make it easy to write applications. As with any framework it is essential to understand whats going on under the hood. Hidden exceptions can impact the overall performance. Without knowing about these exceptions its impossible to solve this problems that lead to the exceptions.
When specifying the full path, the ViewEngine is not going to resolve the name with the defined search locations but is using the full qualified filename as it is passed as parameter.
If you want more information on how to solve this and other problems on the .NET Platform you might also be interested in my latest White Papers about Continuous Application Performance for Enterprise .NET Systems