james mckay dot net

because there are few things that are less logical than business logic
15
Mar

If part of your framework is not fit for purpose, don’t use it

I have a long-standing gripe about web.config files. They are where you are “officially” supposed to put all your application’s configuration settings, but the framework throws in a whole lot of other so-called configuration settings that are, to all intents and purposes, code. Such as HTTP modules, assembly references, which version of the C# compiler to use, and so on.

This is bad. A well-designed application configuration file will only contain settings that vary from one deployment to the next. Anything that is the same across the majority of deployments should be set in your code either by convention or by default values. Anything that doesn’t change from one deployment to the next is not configuration, but code.

But why not just stop using web.config for your app settings and connection strings altogether? There’s nothing stopping you from writing your own configuration class which pulls in all your application settings and connection strings from a JSON file in the parent directory to your application root, or in the Windows registry, if that’s what you need to do.

Build scripts are another example. What language do you use to write your build scripts? Chances are, you either use NAnt or MSBuild. But both of these are XML-based, unwieldy, tricky to learn and use, and somewhat limited. What’s to stop you using Python or Ruby instead, or even batch files, for instance? They can do everything that NAnt and MSBuild can do and more, they are much simpler to understand and edit, and you can leverage the knowledge involved elsewhere.

Just because the framework provides you with an “official” way of doing something, it doesn’t mean you have to use it. Using a different approach to the officially touted way may sound a bit radical or perhaps even iconoclastic at first, but it makes perfect sense once you think about it. After all, if the accepted wisdom passed down from Redmond is not fit for purpose, blindly sticking with it even though it gets in the way is just cargo cult programming.

30
Apr

Why I hate web.config

One thing that is vital when deploying web applications is that you should be able to reduce the process of deploying upgrades and changes to as few steps as possible. Furthermore, every step should be a no-brainer — so simple that the scope for fat fingering something is strictly limited.

This kind of thing is acceptable:

  1. Get the appropriate stable build from your daily build server.
  2. FTP it onto the web server into a directory in an appropriate location. (Even better: have an option in your build script to do this automatically.)
  3. Change the IIS settings to point to the new version.
  4. You’re done!

Now in order to do this effectively, you need to build some foundations into your project. You need to isolate every setting that varies between your production environment and your developer box and put them in a separate location outside the website’s hierarchy that does not change from build to build.

These settings are purely concerned with server-specific configuration settings. They change from one machine to the next and will be different between developer machines and the production server. Examples include connection strings, SMTP server details, custom errors and trace settings. They aren’t necessarily stored in your source control, except as a sample file for documentation purposes, and they should definitely not be deployed afresh to the server with every build.

There are other settings that are tied much more closely to the code itself. Examples include HTTP handlers and modules, assemblies referenced in the <compilation> section, and all the additional stuff that ASP.NET Ajax or ASP.NET 3.5 adds to tell it that you’re using the C# 3.0 compiler, not the C# 2.0 compiler. These settings may change from one build to the next, but they are the same on every machine where they are used. They are, to all intents and purposes, code, and should be treated as such, kept in your source control, and deployed unmodified to the server with every new build.

Unfortunately, web.config mixes the two willy-nilly in a thoroughly cavalier way, with the result that there are several additional, more complex and error-prone steps that you need to take:

  1. Locate the previous build.
  2. Copy the web.config file into the new build.
  3. Merge in the changes manually.

These steps are less straightforward and provide much more scope for error. What if you forget to do them, make a dog’s dinner of merging in the changes, or worse, introduce some subtle and mysterious bug that isn’t there on your development machine?

ASP.NET 2.0 added a new feature to sort this mess out. You can now specify an alternative file for your <appSettings> section. By doing <appSettings file="..\myappsettings.config" /> you can even specify a file outside your web application root. Whoopee! Problem solved!

Not so fast. What about the settings that don’t fit in to <appSettings>? For example, connection strings now go in the <connectionStrings> section; custom errors should be enabled on the server but disabled on your development box; tracing should be enabled on your development machine but not on the server; and so on.

It turns out that these too have an option to allow you to reference external files. You can set, say, <connectionStrings configSource="blah" /> to put your connection strings in a separate file. Unfortunately, unlike with <appSettings>, you can’t put this outside your application root.

Meh. Why not??? This is a major pain in the neck — especially for <connectionStrings>.

To make matters worse, there are some elements that straddle both camps. <compilation> is the most obvious example. It needs to have the attribute debug="true" on a development server, but in production you will need to insert debug="false" for improved performance. However, within your <compilation> element, you have a list of additional assembly references for things such as the ASP.NET Ajax extensions. And you can’t put these in a separate file.

All in all, configSource and <appSettings file="blah" /> go some of the way towards solving the deployment problem. Unfortunately, they still have limitations that are awkward and hobble the process and are a major annoyance.