Protect Your Ass, Redux

Another flaw in the human character is that everybody wants to build and nobody wants to do maintenance.  - Kurt Vonnegut

I've written several times about the importance of having a serious backup strategy for your production web server, mostly about ways to backup the Registry. But there are a few other components of a good emergency recovery strategy that are important as well.

A significant percentage of developers and webmaster / administrators run production sites on production machines and have no reliable backup strategy for the components of the machine that are critical to the successful operation of IIS. The mere fact that up to now you haven't had a production server blow up on you may actually have increased the statistical likelihood that you will experience such a failure!

The three critical components to be protected and backed up -- with an easy path to restore them - are the Windows Registry, the IIS Metabase, and the .NET Framework machine.config file.

Why do you need to do this?  Simple:

  • You could have a power failure or some similar glitch that occurs while the Registry is being written, rendering it corrupt.
  • Some third party (and even some Microsoft) software may not uninstall correctly, leaving Registry baggage behind that renders IIS inoperable.
  • Some software may not uninstall correctly, leaving the metabase file and / or your machine.config file in an unstable state, or leaving them as malformed XML, which will prevent IIS from functioning.

Any one of the above glitches can leave you with either a machine that won't boot, a machine that boots but doesn't run correctly, or an IIS installation that no longer works. If you do not have a reliable way to "go back" on these files to a time when the system was stable and working, you're toast.  Add to that the stress of running a public or large corporate intranet site that no longer functions, and you have bought yourself big problems. Hey - if you are the kind of person that just thrives on stress, stop reading now!

The Windows Registry

The most reliable way I have found to back up the Registry is Lars Hederer's ERUNT. Accept the default installation features, and it automatically backs up your Registry to a dated folder under C:\Windows\ERDNT\AutoBackup each day your machine is rebooted.  Simply execute the ERDNT.EXE file in that folder, and your Registry from that date is restored. Reboot, and you are fixed. You can even execute this file from a Recovery Console window if your OS won't boot. ERUNT runs on all versions of the Windows OS, including 64-bit versions. It's saved my butt several times; I won't run a Windows machine without it.

The IIS Metabase

In IIS 6.0, the metabase is an xml file that is located at  C:\Windows\System32\inetsrv\config

IIS7's "metabase" is actually an XML configuration file that should be very familiar to you since it is similar to ASP.NET's web.config. It is called applicationHost.config and is located in C:\Windows\System32\inetsrv\config

You can easily back up the IIS Metabase  or the machine.config file with a simple batch file, and by adding it to the Startup folder in your ProgramFiles, this file will be automatically copied to a dated file in your backups folder. Example batch file that backs up both files:

@For /F "tokens=2,3,4 delims=/ " %%A in ('Date /t') do @(
    Set Month=%%A
    Set Day=%%B
    Set Year=%%C

copy C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config c:\backups\machine.config_%Year%%Month%%Day%
copy C:\Windows\System32\inetsrv\config\applicationHost.config c:\backups\applicationHost.config_%Year%%Month%%Day%

REM SEE C:\Windows\System32\inetsrv\History for backups of the IIS 6.0 Metabase


You can create a shortcut to your batch file in your backups folder. Then in Start / Programs / Startup, right - click and choose "Explore". Drag your shortcut from the one Explorer folder into the Explorer view of the StartUp Programs folder. Reboot your machine, and you'll see your backup files. There are other ways to run files on boot without a user having to log on to the machine, they involve registry settings and I don't cover them here.

NOTE: To access backup and recovery tools for Windows Server 2008, you must install the Windows Server Backup, Command-line Tools, and Windows PowerShell items that are available in the Add Features Wizard in Server Manager. This installs the following tools:

• Windows Server Backup Microsoft Management Console (MMC) snap-in

Wbadmin command-line tool

• Windows Server Backup cmdlets (Windows PowerShell commands)

Each of these commands or batch files can also be set up to run under Task Scheduler, say once a day or once every 3 days, whatever makes sense for you. In this case, the tasks will run automatically and nobody has to log on to the box.

Don't say that all this is a "great idea, I'll get around to it". Just do it! I hope you don't have to thank me later. But -- you probably will!


ASP.NET Quick 'n Dirty Exception Logging*

If you need an easy way to handle logging exceptions in your ASP.NET web application but want to avoid all the complexities of using a logging library and / or setting up all the database "Stuff", here is  an easy way to handle it:


In web.config:

    <add key="logExceptions" value="true"/>
  </appSettings > 

In Global.asax.cs:

public class Global : System.Web.HttpApplication
        public static bool LogErrors = Convert.ToBoolean(ConfigurationManager.AppSettings["logExceptions"]);


protected void Application_Error(object sender, EventArgs e)

    if (LogErrors)
    Exception ex = Server.GetLastError().GetBaseException();
               DateTime.Now.ToString() + ": \r\n" + ex.Message + "\r\n" + ex.StackTrace);


What this does is grab the Exception (the one you didn't handle -- right? :-) and use the neato File.AppendAllText static method which will create the file if it isn't there, append your text, and close the file all in one swoop.    We write to our file in the /App_Data folder because that folder is automatically excluded from file change notification. We don't want our app recycling on us just because we logged an exception.

So by simply changing the appSettings element "logExceptions" to true, we can turn on "poor mans exception logging".


Silverlight Links

Thanks to an active developer / blogger community, my ittyurl.net site (which I originally developed for myself, but later realized that if I made it public, others might find it useful) -- now has a large number of active Silverlight links to their work, along with a few that I have added. Check it out if you are interested in Silverlight - I certainly am!


* Disclaimer
All increased intelligence due to reading this matter becomes the property of Peter Bromberg's UnBlog (hereafter referred to as "The UnBlog") and will not be acknowledged or returned. Neural damage is the responsibility of the reader. Attempts to enhance mental capacity as measured by standardized metrics neither legally nor ethically compel The UnBlog to make commensurate enhancements in quality or content. Readers with demonstrated cranial enlargement or cortical thickening may be required to sign a liability/publicity/copyright release and to appear in an article on the UnBlog, provided they are also the star of an upcoming motion picture.
The UnBlog reserves the right to cancel, terminate, or modify people who use brain-embiggening technology because look, dude, this is Peter Bromberg's UnBlog and we don't fool around. (acknowledgements to wired.com).


MVP Summit -- and a Lesson from Chief Seattle

"Day and night cannot dwell together." -- Chief Seattle


The MVP Summit in Redmond / Seattle this year is proving to be valuable, at least to me. I've been focusing mostly on the tracks around Silverlight and where it's going, and it appears to me that this product is going to evolve quickly into  a killer platform that will be capable of producing enterprise - level browser based applications that do video, high-powered vector graphics /animation, and data access including ws* SOAP, REST, HTTP, TCP and even UDP transports, LINQ,  and can handle cross - domain calls with the appropriate security xml files in place. DataBinding is done, and there's more coming which will show up in the next Beta coming -- well -- let's just say "sometime soon".

But the best lesson was one we learned in real life at Maggiano's in Little Italy in Bellvue, in a building hosting a Microsoft office and where the language groups dinner was held for all the VB.NET, C#, SQL and other MVP's.  It was a lesson about the importance of communicating with your customer and how learning to think "outside the dogma" is a real sign of leadership.

I'll explain. We took the bus from the Microsoft Campus to Bellevue, and walked into Maggiano's, which is a large sort-of high end classic Italian restaurant. There were wine and beer, an open bar, and an assortment of excellent hor's d'oevres, buffet style, to get you started.  I, Robbe Morris, Bill Jones and Ken Spencer sat down at a small booth-style table in the room adjoining the bar and began enjoying our drinks and having a wonderful, lively conversation.

After we had been at our table for some 45 minutes the trouble started. A waiter / manager type came up and told us we would have to move  because they couldn't serve us food at our table.  We immediately decided that this was rude and somewhat customer-unfriendly since there was no visual or other indication at this table when we first sat down to indicate this. Besides, everybody had already been seated and it didn't look like there were 4 seats together for our group. So we determined we'd take a stand.  After all, this table was in the same room where all the MVPs were being served, the only difference being it was smaller and not pushed up against others in a long row. Otherwise, there was no difference at all to a server; the aisle between our table and the long rows of larger tables where most MVPs were seated provided equal access to a server with no visible impediments.

Well, it didn't work out well at first. We ran up against the "Manager Mentality" dogma of "no, we cannot / will not change, this is the way it is, and tough titty on you if you don't like it".  I took a stand and told the manager that we weren't going to move and that we expected to be served just like everybody else, at the table we'd been sitting at for some 45 minutes.  We got no response. They decided to give us the "Ignore" treatment.

Raj, one of the Microsoft presenters, who was present at the dinner, came over and offered to intercede on our behalf. I don't know what he said, but I think he mentioned that Microsoft was spending upwards of $40,000 to entertain it's MVPs and would they please break with protocol and serve us.

After another 45 minutes with everybody at the main tables already into their main course, we still hadn't been served. It was at this point that I found out there was another small group seated at a booth just outside the kitchen that had a problem similar to ours. They were just now being served their dinner - apparently the manager thought that they were us and believed he had met his obligations. So finally, we got that straightened out and we got our food. Shortly thereafter, we were told that Microsoft had asked to have the bar opened for us to have "anything we want" - a nice touch.

So, with a Grey Goose martini (up, with two olives) in hand, I had a chance to enjoy the last of my companionship with my tablefellows and we made our way back to the hotels.  The food was great, the drinks were great, but we all learned the lesson preached by great Chief Seattle in his speech of 1854:

Don't fight the White Man. We will move to the reservation.  Seattle was explaining to his people that sometimes you need to suspend dogma in the name of good relations.

It's a lesson that we all should learn when dealing with customers. Sometimes it is more expedient and sensible to break with protocol, stick a plate of Lasagna on the errant customer's table, and avoid conflict in the name of good customer relations. It is usually not a big deal to learn to do this, you just need to learn to stop thinking like a robot and start using your, er - noodle.



How to get Visual Studio 2008 Pro for Free

I often read posts and other comments from people who complain that Visual Studio is too expensive, etc. Sometimes they aren't even aware that the free EXPRESS versions exist.

Well, don't fret. There are two ways you can get Visual Studio 2008 (as well as Microsoft Expression Studio, XNA Game Studio, Sql Server 2005,  and even Windows Server OS)- all free.

1) If you are a university student, find out if your school has an MSDN AA Account. This is your ticket to a free copy.

2) Go to DreamSpark. Dreamspark is Microsoft's free software site for students. All you need to do is log in with your Live ID (Passport) account, and download your free stuff. You'll need to verify you are a student by choosing your school. If it's not listed, DreamSpark has partnered with JourneyEd to verify U.S. students at schools throughout the country. JourneyEd will help you through a simple verification process – it will be just like an online purchase, but it will cost you nothing. At the end of the process you’ll get an email with your personal verification link back to DreamSpark.  Just click the "Other verification options" link.

Easy, huh?


Modifying The AppSettings Section in Web.Config


I see frequent questions related to "how can I change web.config programmatically?" -- of course if you do this in a running app, it is going to recycle and you will lose all your Session, Cache and Application items. However, there can be times -- for example if this is part of an installation page and you need to save the entered items -- when this is necessary. Since most of the time these values will be stored in the <appSettings... section, here is a simple method to facilitate this:


public void Modify(string key, string value)
Configuration configuration = WebConfigurationManager.OpenWebConfiguration("~");
AppSettingsSection appSettingsSection = (AppSettingsSection)configuration.GetSection("appSettings");
   if (appSettingsSection != null)
       appSettingsSection.Settings[key].Value = value;