Key Configuration Settings When Deploying a Web Application
By Scott Mitchell
Introduction
The configuration information for an ASP.NET application is stored in one or more XML-based configuration files named Web.config.
The default configuration settings for all web applications on the web server are spelled out in the Web.config file in the
$WINDOWS$\Microsoft.NET\Framework\version\CONFIG folder. These default settings can be added to over overridden for a specific
web application by the Web.config file in that application's root directory. Moreover, these configuration settings can be customized
for a web application on a folder-by-folder basis by adding Web.config files to the application's subfolders.
The Web.config file spells out an array of configuration settings, including: database connection strings, authentication and URL authorization
rules, and the behavior that unfolds when an unhandled exception occurs, among many others. Many configuration settings differ between the development
environment and the production environment. For example, when you are developing an ASP.NET application on your desktop you are likely using a different
database than when the application is in production. Consequently, the database connection strings in Web.config need to be updated
when deploying an application.
Some of these types of configuration settings must be changed when deploying an application, like database connection strings. Failure to modify
the configuration information when deploying will cause the web application not to work in production. These types of configuration settings are easy
to remember to change. But there are a number of configuration settings that should be changed when deploying an application, but if they
are not changed the application will still work in production. These configuration settings are easy to forget to change, and forgetting to change
them can reduce the performance of your application or make it more vulnerable to attacks from malicious users.
This article details a handful of configuration settings that fit into this latter category. Read on to learn more!
Enabling Custom Errors
In .NET applications, an illegal operation - an invalid cast, attempting to reference a null value, trying to connect to a database that's been taken
offline, and so on - raises an exception. Exceptions can be caught and handled directly in code through the use of Try / Catch
blocks. For ASP.NET applications, if the exception is not handled in code, it bubbles up to the ASP.NET runtime, which raises an
HttpUnhandledException. How the ASP.NET runtime
responds to an HttpUnhandledException depends on your application's configuration settings. The runtime will do one of three things:
Display a generic error page that simply reports that a runtime error has transpired,
Display an error page with error details, including the exception that was raised and, if the code is compiled with debug symbols, a stack trace
and a few lines of code around where the exception was thrown.
A custom error page, which is an ASP.NET page that you create that the user is redirected to.
The Web.config file contains a <customErrors> element
that dictates which of the three outcomes detailed above unfolds in the face of an unhandled exception. The mode attribute
of the <customErrors> element can have one of three values:
On - the "Runtime Error" page or custom, user-friendly error page is shown to all visitors in the face of an unhandled exception.
Off - the exception details page is shown to all visitors in the face of an unhandled exception.
remoteOnly - remote users - those not coming through localhost - see the "Runtime Error" page or custom, user-friendly error
page; local visitors - the developers, typically - see the exception details page.
When an unhandled exception occurs in a production environment it is important that the user not see the exception details page, for such information could
constitute a security risk. For instance, the line of code where the exception was raised might include sensitive information in the source code, such
as an ad-hoc SQL query or, even worse, a database connection string. Even if the code shown in the exception details page doesn't reveal any such
tidbits, by showing the details of the exception you are revealing some of the inner workings of how your application works to the visitor. This may give
a malicious visitor additional information on how to compromise your application. Furthermore, the exception details page is ugly a bewildering to most
users. It's best to show them a custom error page whose look and feel mimics the look and feel of your website.
Use Health Monitoring or ELMAH to Log and Notify Developers When an Unhandled Exception Occurs
If you notice that your web application on production is generating unhandled exceptions, you may be tempted to update the Web.config
file's <customErrors> element's mode property to Off so that you can see the error details and fix
the cause of the problem. The downside with this approach is that while you have custom errors disabled, all other visitors are seeing the same exception
details screen as you are. Ideally, an ASP.NET application in production should log all unhandled exceptions to a database and e-mail the details
to the site's developers. That way, you are immediately alerted whenever an error occurs in production and you can consult the error log and leave
the custom error logic in tact rather than trying to reproduce the error while having custom errors disabled.
Turn Off Output Tracing
Output tracing enables developers to display request information at the bottom of a page or from a special URL, Trace.axd. Tracing
can be configured at the page-level through the Trace attribute in the @Page directive, or can be configured for the entire
web application using the <trace> element in Web.config.
Having tracing enabled in a production environment is ill advised because the trace log displays sensitive information including cookies,
information stored in session state, and any diagnostic information written to the trace log. With tracing enabled, a malicious user could visit
the Trace.axd page and see the trace logs for the last several requests to the application.
To prevent trace information from appearing in a production website you can either disable tracing altogether or configure it so that it's only accessible
when coming through localhost. The <trace> element has two Boolean attributes that specify these particular settings: enabled
and localOnly. For more information see the <trace> element
technical documentation and Tracing in ASP.NET.
Turn Off Debugging Support
When an ASP.NET page is visited for the first time or for the first time after it has been modified, the declarative markup in the page is automatically
compiled into a class and is then "executed" by the ASP.NET runtime in order to generate the content to return to the requesting client. This conversion
from declarative markup to source code, and the source code's compilation, is seamlessly handled by the ASP.NET runtime when the request is made.
Various settings regarding this compilation process can be configured via the <compilation>
element in Web.config. Furthermore, the source code in the ASP.NET pages' code-behind classes can either be compiled automatically by
the web server or explicitly by the developer before deployment. If you build your application using Visual Studio's Web Site Project model and deploy
the code files (rather than a compiled assembly) then you are using the automatic compilation model, and the <compilation> element's
settings also apply to the auto-compilation of the code-behind classes.
The <compilation> element includes a debug attribute that indicates whether to compile the code in debug mode or in
retail mode. Code compiled in the debug mode includes addition debug symbols and other performance-draining information that is required during debug time.
For applications in the development environment, where you will actively be debugging your application, it makes sense to have the debug attribute
set to true. But when deploying your application, make sure you set this attribute to false. Doing so will improve the performance of your application
by more quickly compiling these resources and using less memory when a page is visited.
"This last point is particularly important, since it means that all client-javascript libraries and static images that are deployed via
WebResources.axd will be continually downloaded by clients on each page view request and not cached locally within the browser. This
can slow down the user experience quite a bit for things like [ASP.NET AJAX], controls like TreeView/Menu/Validators, and any other third-party
control or custom code that deploys client resources. Note that the reason why these resources are not cached when debug is set to true is
so that developers don't have to continually flush their browser cache and restart it every-time they make a change to a resource handler (our
assumption is that when you have debug=true set you are in active development on your site)."
To get optimal performance from your website, make sure that the Web.config file in production has the <compilation>
element's debug attribute set to false.
Forcing Deployment Configuration Best Practices Using the <deployment retail="true" /> Setting
If you are deploying your web application to a machine that you have control over, such as a web server within your company's intranet or a dedicated
web server at a web host provider, you can use the <deployment> element
in machine.config to force all applications on the web server to adhere to the recommendations provided above (namely, using a custom
error page, disabling output tracing, and not having the auto-compiled code compiled in debug mode). Simply add the following markup to the
machine.config file within the <system.web> element:
<deployment retail="true" />
Note: You'll find the machine.config file in the $WINDOWS$\Microsoft.NET\Framework\version\CONFIG folder.
That's all there is to it! To undo this setting, you can remove this element or set the retail attribute to false (the default). Keep in
mind that the <deployment> element can only appear in machine.config, and not Web.config, and applies
to all websites on the server.
Conclusion
There are a variety of configuration settings relevant for an ASP.NET application, and some of these settings should differ based on whether the application
is in a development environment or a production environment. This article looked at three configuration settings that do not need to be changed
when deploying an application, but definitely should be changed for performance- and security-related reasons. If you have control over the web server
you can force these best practice configuration settings by adding <deployment retail="true" /> to the server's machine.config
file.