A harsh reminder about the importance of debug=”false”
Performance By Dave Ward. Posted September 19, 2012This post was originally going to be about improving performance in ASP.NET MVC websites that use the Razor view engine. Instead, it became a cautionary tale about just how important it is to run your ASP.NET sites in release mode if you care anything at all about performance.
The whole thing began when I tweeted about some rough benchmarks on ASP.NET MVC controller actions vs. ASP.NET Web API endpoints last week, and Ashic Mahtab asked me to also run some benchmarks comparing MVC’s Razor and WebForms view engines. When I ran those benchmarks and replied to him with the result that Razor was running much slower than WebForms, he had this suggestion:
@encosia did you remove the web forms view engine for the razor test?
— Ashic Mahtab (@ashic) September 2, 2012
Good idea. I did that, re-ran the Razor benchmark, and the magnitude of the change really surprised me. Razor was over twice as fast with the WebForms engine removed!
I knew that removing the WebForms view engine improves the performance of Razor view resolution, but I didn’t expect the difference to be nearly that significant. So, why was the difference so large?
The search for a view
Before we get to the fallacy in my benchmarks, you may be wondering why removing the WebForms engine made such a big difference. The root cause can be seen in an error message that’s probably all too familiar if you’ve spent any time working with ASP.NET MVC:

By default, MVC is configured to resolve named views by searching for files that match the WebForms view engine’s naming conventions first. Only after scanning unsuccessfully for those first four variants does MVC search for Razor views.
As you can imagine, running through the process of checking four unused locations first for every return View() and Html.RenderPartial is quite wasteful if you aren’t using the WebForms view engine in your project.
Removing the WebForms view engine
If that view resolution inefficiency bothers you, it’s easy to remove the WebForms view engine from the mix. Just drop code something like this in your Global.asax.cs’ Application_Start event:
ViewEngines.Engines.Clear(); ViewEngines.Engines.Add(new RazorViewEngine());
In debug mode, that small change results in a significant performance boost because MVC will be able to locate views four I/O operations quicker. Often, the very first location MVC searches is now the correct one for C#-based Razor views.
Benchmarking bad
I wanted to get a better idea of what impact removing the WebForms view engine would have on a real-world page. With the plethora of view resolutions necessary on a complex page, a real site is a more interesting test than benchmarking a simple DateTime.Now. So, I found an older MVC site that I had recently migrated from WebForms to Razor, benchmarked it, removed the WebForms view engine, and benchmarked it again.
The results spoke for themselves. Before, with the WebForms view engine’s search locations taking precedence over Razor:
1,225 requests per second across 1,000 concurrent connections. Not too shabby, but now let’s eliminate the WebForms view engine from the mix and try it again.
Running the same benchmark with only the Razor view engine, using the Clear/Add approach shown earlier in this post:
2,671 requests per second now, testing the same page with the same benchmark settings. Two lines of code have resulted in roughly twice the performance!
That’s a pretty impressive improvement, but incredibly misleading.
All for naught
At this point, you might be thinking that the point of this post is to remove the WebForms view engine if you’re using Razor. After all, twice the performance is pretty compelling.
Quite the opposite, it turns out that my benchmarking was pointless because I was running these sites in debug mode locally. I’ll explain why that matters in a minute, but first let’s look at the same benchmarks with debug set to false.
First, I benchmarked the default view engine setup again. With the WebForms view engine’s search locations coming before Razor’s, these were the results:
Now, with the WebForms view engine removed and only Razor’s view resolution in play:
We’ve gone from a 100% performance increase to a meager 1-2% increase. What in the world happened? Wouldn’t you expect the performance optimizations in release mode to apply equally in both scenarios?
So, what happened?
In debug mode, view resolution is optimized for ease of development. MVC iterates through the view resolution process each and every time your code renders a named view. That’s helpful since you obviously do want the environment to respond immediately to your changes when you’re working on a site.
In release mode, however, MVC’s view resolution is optimized for performance. When a view location is successfully resolved in release mode, MVC caches the result of that lookup and doesn’t need to perform another filesystem search when it encounters a reference to that named view again.
The result is that the apparent inefficiency of having WebForms’ naming conventions take precedence over Razor’s becomes negligible after the first resolution. So long as you don’t allow your production sites to run in debug mode, the view resolution issue is almost entirely eliminated.
debug=”false” – not just for view engines
View resolution caching is just one reason of many to ensure that you do not run your production sites in debug mode. Other serious drawbacks include:
- Timeouts – Have you ever noticed that you can spend an indefinite amount of time fooling around in the debugger without a halted request timing out? That’s because debug=”true” disables timeouts entirely, which is never a good idea on a live site.
- Bundling and Minification – ASP.NET’s new web optimization feature can automatically bundle and minify your JavaScript and CSS, but it only does so in release mode. When you run with debug=”true”, bundles are served as separate, unminified, uncombined script references with short caching headers. That’s important during development so you can read/debug your JavaScript code, but it defeats the entire point of the optimization exercise in production.
- WebResource.axd caching – Speaking of client-side resource optimization, resources served through WebResource.axd include aggressive caching headers in release mode. In debug mode, they are not cached at all.
There are even more reasons to avoid debug=”true” in production, but the items above are a few that I think are less obvious since they aren’t directly related to benefits associated with release mode compilation. It’s easy to think of debug and release in terms of compiler optimization and debug symbols since the configuration switch is on the “compilation” element in web.config.
So, it’s important to be mindful that this single “compilation” setting controls a wider range of your site’s functionality than you might expect.
Conclusion
Of course, you probably already know that you shouldn’t deploy a live site in debug mode, but how many times have you seen it happen anyway?
There’s always a “good” reason, like coaxing more detailed error messages from a site that only breaks in production, or disabling client-side resource caching to fix issues when rolling out new assets. Stretched as thin as most of us are, it’s all too easy to leave that site running in debug mode after the immediate issue is resolved.
So, let my benchmarking blunder be a reminder to check today and be sure that you don’t have any production sites running in debug mode.
Similar posts
What do you think?
I appreciate all of your comments, but please try to stay on topic. If you have a question unrelated to this post, I recommend posting on the ASP.NET forums or Stack Overflow instead.
If you're replying to another comment, use the threading feature by clicking "Reply to this comment" before submitting your own.







This is a good reminder to use your Web.Release.config to automatically change your configure anytime you public your site to live. Prevents releasing the site in Debug mode.
Thank you for this hint, i wasn’t know about it before…
Sadly this feature is only available from VS2010
Any way to configure ViewEngines to only search cshtml?
I ran into this Stack Overflow thread about that while I was doing research for the post. I think that would need to be tweaked for MVC 4 if you wanted to retain support for .mobile.cshtml views though.
Great information. How can I verify programmatically (at run-time) that debug is turned off? I’m thinking we’ll set up a monitoring page on our production servers to confirm this.
HttpContext.Current.IsDebuggingEnabledshould befalsewhen debug is disabled in the web.config.What are you using to benchmark?
Apache Benchmark (ab.exe).
Same question as Joey, in addition, just curious as to what OS / IIS are you developing it locally? As I understand it, non-server editions limits the number of concurrent connections to IIS.
http://www.jpelectron.com/sample/WWW%20and%20HTML/IIS-%20OS%20Version%20Limits.htm
Greatly appreciate you for letting me know so I can benchmark my apps properly using your tool.
Thanks.
The tests were using Apache Benchmark, running under Windows 8 Enterprise.
Great post !! Thanks Dave
I suggest using the System.Diagnostics.Stopwatch class instead of DateTime.Now for more accurately tracking elapsed time.
http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.start.aspx
The DateTime.Now mention wasn’t related to timing for the benchmark.
nice show !
@Dave: why not? it’s a common bad (missleading) practice.
Why not what?
Debugging shouldn’t be handled by the language itself – it should be thrown on the programmer to develop his own routine to debug his application. That’s why PHP does not have internal debugging.
I do not want to get into a debate on which language is better – but there are some settings in .NET and PHP that are really terrible and shouldn’t be there in the first place.
I like the way you lay this out as a narrative. I saw the performance improvements and thought “yes, it’s reducing the IO, of course”, but the punchline is great. Of course Microsoft thought of that and cached accordingly in release mode. Seems so clear after you lay it out that way.
The hardest part about running in release mode is losing detailed stack traces and thus running on the assumption that the app is bug free. Sad fact is various contracts I’ve worked had high enough production error counts that the detailed stack traces from prod were necessary on a daily basis. Toxic, yes. But the culture of “fix it in prod” is more pervasive than you’d think. Though if this is a problem on your app, performance is the least of your concerns!
Thanks for the great post Dave.
what did you use to run these tests
Apache Benchmark.
Nice article Dave. But still razor compiled the code as /debug+ while webform /debug-. See this http://aspnetwebstack.codeplex.com/workitem/543
That’s interesting; I didn’t know that. The benchmarks I ran had Razor coming out ahead of WebForms though anyway. Have you seen evidence that Razor is significantly slower due to the debug compilation?
I haven’t. But I have seen at lot of places where expert are saying that it will impact the performance. Here are some the one places,
http://books.google.ae/books?id=fCJEEjeLRVgC&pg=PA294&lpg=PA294&dq=C%23+compiler+%22csc%22+debug+performance&source=bl&ots=HkE3JWEu-5&sig=s6iRrfZDi5vbdgG7djZpKkdmwlY&hl=en&sa=X&ei=ChF8UNToCJOQhQeYp4HgBA&sqi=2&redir_esc=y#v=onepage&q=C%23%20compiler%20%22csc%22%20debug%20performance&f=false
http://stackoverflow.com/questions/3226157/where-can-i-modify-detailed-c-sharp-compiler-optimization-settings-in-visual-stu