Thursday, August 9, 2007

To those few of you who actually visit this blog, you may have noticed the recent lack of new activity.

I am in the process of consolidating these nerdy tidbits in a dedicated site, I found at the outset that blogspot was bad for displaying code snippets unless you spend a lot of time formatting your template. I'm simply not that smart. To get around this, I often forwarded you to my live spaces blog. What a pain, I agree.

So, it may take awhile, but look for this blog to shrink and the new site to grow. The live spaces blog will go away, and you can bookmark . For now, I have created a feed to the site, down below (near the Google ads ;)).

Thanks for visiting!

Monday, July 30, 2007

Friday, July 27, 2007

Tuesday, July 24, 2007

Friday, July 20, 2007

File Attribute in Web.Config

A previous post provided a simple example for decoupling various configuration sections from your web.config by using the configSource attribute to point to external files. This feature is available in 2+.

Another option is the File attribute. An example is provided in the following blog. I think this attribute has more going for it than the configSource attribute.

Default + Optional Override

The file attribute allows you to keep default settings in your web.config. If .NET finds the specified configuration specified by the file attribute, it overrides your defaults. This provides you with the option to decouple your configuration from web.config:
If finds a "user.config" in my application directory, it uses those settings.

Available in ASP.NET 1.1

Given the file attribute's availability in 1.1, I don't see the added value that the configSource attribute provides in 2.0. Comments?

File Must Reside within the Application's Physical Directory Structure

To further decouple the application from configuration, I tried specifying the file in a virtual location. This would allow me to stage configuration updates separately from application updates. Like the configSource attribute, it was no dice. Rats.

Wednesday, July 18, 2007

Product Recommendation: Beyond Compare

Your application works in your QA environment, but not in Production. The IIS configurations are identical. You've verified database connectivity and firewall rules. In fact you've ruled out everything but the code. Is it the same in each environment?

Use Beyond Compare to verify. It quickly surfaces file system differences in a nice GUI.

Side By Side Directory Comparison
The directory comparision displays a side-by-side listing of the "source" and "compare to" directories. Use the "<>" option to display only the differences:

Line by Line File Comparision
Differences will be highlighted via color codes. When you want to drill down into a specific file difference, simply double-click to view a line-by-line file comparison:


Use the referee icon to enable/disable compare options. For instance, an extract from Visual Sourcesafe will yield a new date/time stamp, even if you know the file on the compare directory is identical. Unflagging the "Timestamp" folder comparison criteria will remove this comparison "noise" and allow you to spot more meaningful differences.

Tuesday, July 10, 2007

VBScript - Read From Registry

Here is a quick and dirty function for reading a registry value using the WScript.Shell object:

    function readFromRegistry (strRegistryKey, strDefault )
  • Dim WSHShell, value

  • On Error Resume Next

  • Set WSHShell = CreateObject("WScript.Shell")

  • value = WSHShell.RegRead( strRegistryKey )

  • if err.number <> 0 then

  • readFromRegistry= strDefault

  • else

  • readFromRegistry=value

  • end if

  • set WSHShell = nothing

  • end function

    str = readfromRegistry("HKEY_LOCAL_MACHINE\SOFTWARE\Adobe\ESD\Install_Dir", "ha")
    wscript.echo "returned " & str

Monday, July 9, 2007

Global Assembly Cache

Moved to

BlogSpot Title Entry Bug

For the past few days, I noticed it was difficult to create a new posting and give it a title. The Title text box appears to be disabled:

To get around this, place your cursor anywhere along the upper edge of this text box.

...back in business!

Wednesday, June 27, 2007

Beware of Nested Web.Config's!

Problem with Nested Web.Config's
If your web servers host a complex IIS tree, beware of nested ASP.NET applications and their respective web.config's. If a "parent" ASP.NET application declares a type (and therefore a dependency on an assembly), the "child" application inherits this declaration. See the following msdn article for lengthy discussion.

What this means, ultimately, is that your child application will be looking for a dll in its /bin folder. When it doesn't find it, the child application throws a yellow screen.

Here is an example. I've set up http://localhost/MyApp, a do-nothing app that happens to implement the ASP.NET 1.1 URL Mapping Module discussed in a previous blog. I've built another do-nothing app, and for demonstration purposes created a virtual directory hosting this app under the do-nothing parent, http://localhost/MyApp/MySubApp.

See what happens when I try to run the child app from a browser...

To resolve the error above, you can take one of the following approaches:
  1. Copy the assembly to the child's /bin folder. This works, but it's sloppy configuration. Why xcopy dll's across your file system, introducing redundancy and superfluousness?
  2. GAC the assembly. That way it's available to the child, and any other application, whether or not it's needed.
  3. Restructure IIS to avoid the problem.

Friday, June 22, 2007

SourceForge.NET's Telnet Library Rocks

Say you need to test your web server's basic connectivity to its SQL database server, or its Oracle database server, or its SMTP mail relay host, etc. You would want to hop on the web server, open a command line console (DOS prompt), and try to connect using telnet commands like:

    Telnet mySQLServer 1433
    Telnet myOracleServer 1521
    Telnet myMailServer 25
What if you don't the necessary access to log on to the web server? That's the problem I have been facing. Our data center was outsourced, servers moved, and stuff stopped working. If your web application doesn't have the basic connectivity we all take for granted, it's not going to tell you your firewall rules are all mucked up; it's just not going to work.

Enter SourceForge.NET's Telnet .NET library. Download this library, add it to your application's references, write a simple web form that tests remote host and port combinations from user input, and you have a helpful diagnostics tool. It is presently saving my life.

Thursday, June 21, 2007

Attaching Lotus Notes links to Outlook Mail

My company has migrated from Outlook/Exchange to Lotus Notes, then back to Outlook/Exchange. With the latest migration away from Notes, we left some vital Notes databases in place. So now we use Outlook for mail, and Notes for repositories.

...Yeah, it's that kind of place. If you've been around awhile and know where things are, you are indispensable :).

Anyway, the great thing about using Notes for email and work was that you could embed all kinds of referral links in your email using "copy as link" at the Notes data and then ctrl+v paste in the email. The ctrl+v doesn't work in Outlook, which is a drag. So here's a work around...

Step 1 - Copy as Link
Go to your Notes document or database (shown below), right click and select "copy as link"

Step 2 - Paste Ctrl+V to a Text Editor

Note the interesting markup

Step 3 - Save the Text File with an .NDL Extension

Step 4 - Attach the .NDL file to your Email Message shown. When the recipient double-clicks the attachment, they go right to Notes!

Tuesday, June 19, 2007

VS.NET 2005 - Where are the Binaries?

VS.NET 2003 - /bin Directory
In VS.NET 2003 when you set up a web application, an IIS virtual directory was automatically created, most commonly pointing to a file system folder in c:\inetpub\wwwroot.

When you compiled your application, a single binary, appname.dll, was created in c:\inetpub\wwwroot\appname

VS.NET 2005 - Where did the Binary go?
If you just started developing in VS.NET 2005, you may be oblivious, happily leveraging your new master pages and themes. Just wait until you try to deploy your application to another server. You'll come to find:
  1. While developing, your application was running under Webdev.webserver.exe, not IIS.
  2. There is no /bin directory. In fact, there is not c:\inetpub\wwwroot\appname directory.

To find your development artifacts, visit C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files . The structure may confuse you -- it's more esoteric then appname/bin probably consisting of files with a .compiled extension. VS.NET 2005 has a new compilation model, a subject for another day.

To move your application into IIS:

  1. Use the Build/Publish Website interface to create a "release directory".
  2. Create a virtual directory that points to the release directory.
  3. Make sure the virtual directory is configured to run under ASP.NET 2.0

Monday, June 18, 2007

ASP.NET 1.1 - URL Mapping

A previous post described how to set up simple URL Mapping in ASP.NET 2.0. To do the same in ASP.NET 1.1, it's almost as simple, if you use Chris Pietschmann's code and instructions.

Just add the custom HTTPModule's dll to your application's bin folder, then tailor your web.config appropriately, and you have what ASP.NET 2.0 provides!

Friday, June 15, 2007

ASP.NET 2.0 - URL Mapping

ASP.NET 2.0 provides features supporting "vanity url's" or "friendly url's". These are useful when you want to distribute simple url's to customers.

Say for instance you have an online store, offering a new product to a segment of customers. The path to the catalog item is
But you'd like to distribute a simpler url:
URL Mapping makes this possible. The following is a much simpler example. Note that it just happens to use the location appSettings overrides described in an earlier blog.
The highlighted section specifies the url mapping. The vanity url's (Diablo_Config.aspx and Diablo_Config.aspx?loc=test) are actually just as complicated as the actual paths (testconfig.aspx and test/testconfig.aspx), but it illustrates what's possible. The following screenshots illustrate what the "customer" sees:

The aspx page that outputs the appSettings is simply copied to the application root and /Test folder for illustrative purposes. If you're interested in aspx (not code-behind) that references app settings, see the following link.

Sunday, June 10, 2007

ASP.NET Deployment Error

Every seen the following error? It is literally littering Microsoft's ASP.NET forum:

It happens when a developer tries to deploy their first ASP.NET application to an ISP's or employer's shared web server environment. Take a close look at the graphic above, particularly the highlighted section. It's a helpful clue, though in most cases it's not exactly correct.

What's most likely is that the application folder was copied to the site on the production server, without configuring the folder as a virtual directory at all. See earlier IIS posts on automating the creation and configuration of virtual directories with VBScript. You can hand these off to your site administrator.

Wednesday, June 6, 2007

"Shredding" your Outlook Documents

Have you ever used the "Tools/Recover Deleted Items..." option in Outlook? A friend tipped me to it earlier this year. If your company uses Outlook for email, get familiar with this option and use it often to clean up after yourself. You don't need to keep personal (or worse yet, incriminating) emails within easy reach of an Outlook administrator.

Deleting Items
You delete email all the time, and are probably familiar with the Outlook "deleted items" folder: (deleted items folder)

To clear space for you mailbox (most administrators enforce a size limit) on the mail server, you probably clear this folder routinely. You do this by deleting all items from the "deleted items" folder, kind of like clearing the recycling bin on your file system.

(emptied deleted items)

Clearing Deleted Items, for Good

To remove the items "for good", go to the Tools/Recover Deleted Items menu option and delete all Outlook documents for a third and final time. The "X" icon takes care of it for you. CYA!

Monday, June 4, 2007

C# Console App Displaying Remote ASP.NET Configuration

The following code, when compiled in a C# console application, will print the AppSettings collection for a remote machine. It accepts 4 arguments:

  1. Machine Name - the network machine you wish to query
  2. Site Name - the IIS site node you wish to query
  3. User Name - user id to log into the remote machine
  4. Password - user password to log into the remote machine
    The app uses System.DirectoryServices.DirectoryEntry to navigate the IIS Tree and recurse through virtual directories, seeking configuration
    The app uses the static WebConfigurationManager class to open and read the AppSettings collections
    The main function is overloaded such that user name and password are optional. When not supplied, the logged in credentials of the executing machine are used.
    In order to read remote configuration, you must run "aspnet_regiis config+" on the remote server.

Thursday, May 31, 2007

Site Monitoring - Simple Tool

You want to ensure that your site is accessible 24x7, and want to be notified ASAP if there is an outtage. Here is a simple recipe.
  1. Create a "KeepAlive" page; a simple page with a static, predictable response. I have created a simple page that displays the Site Name, Web Server Name, and Site IP Address:
  2. Implement a VBScript which makes an http request of the Keep Alive page, returning the response string. The script implements the Microsoft.XMLHTTP object. If the request does not resolve or returns an unexpected result, the script sends an email to the stakeholder (you).
  3. Implement an NT Scheduled Task to run the VBScript (#2) every five minutes. Hopefully, you'll never hear from the tool :)

Tuesday, May 29, 2007

ASPBufferingLimit - IIS5 vs. IIS6

On upgrading a web server from Win2K/IIS5 to Win2K3/IIS6, an old classic ASP application stopped working. This app pulled a large recordset from a SQL database, dumped the records into a large array, and then looped through the array, rendering a grid. I'm not sure why it needed the intermediate step, but of course the developer was long gone from the company. Such is life. Here's the error encountered:

First I ruled out the most obvious and usual offenders during a migration - code and data. Configuring the app on my development machine (IIS5), pulling down the production code and pointing to the production db, the app functioned swimmingly.

Moving on, I researched and came across an IIS ADSI property, "ASPBufferingLimit". Apparently IIS6 sets a lower constraint on the ASP Buffer than IIS5. Good for a healthy web server, but bad for some legacy apps.

The issue was resolved by upping the buffer limit on the IIS6 server. The server administrator accomplished this by running:

    c:\inetpub\adminscripts\adsutil.vbs set w3svc/aspbufferinglimit value
Note: The default setting in IIS6 is ~4MB. The default setting in IIS5 is not visible, apparently, but is rumored to be ~128MB. That seems high to me but I have no choice other than to trust google research :)

Friday, May 25, 2007

Enable IIS 6.0 Extensions using VBScript

If you've worked with IIS 5 and IIS 6, you know that IIS 6 has some tighter default security settings. For example, an administrator must take explicit steps to enable the server execution of ASP/ASP.NET applications. This is accomplished with a few quick clicks, but I'm always looking for shortcuts, e.g.

    Set IIsWebServiceObj = GetObject("IIS://localhost/W3SVC")IIsWebServiceObj.EnableWebServiceExtension "ASP.NET v1.1.4322" IIsWebServiceObj.SetInfo
Taking it a step further, suppose you have a proprietary extension, for instance a dll or exe which serves as an engine to render dynamic html. In other words, say you have a very OLD application. Here's how you would handle that wrinkle:

    Option explicit
    dim IIsWebServiceObj

    Set IIsWebServiceObj = GetObject("IIS://localhost/W3SVC")

    'Enable Proprietary Extention
    IISWebServiceObj.AddExtensionFile "c:\mydll.dll", true, "MyDLL", true, _ "MyProprietaryExtensions"

    wscript.echo "success!"

Wednesday, May 23, 2007

"Visual studio could not identify the version of ASP.NET on the Web server. Do you want to continue?"

I happened upon this warning today when attempting to execute a Project\Copy Project for my web application in VS.NET 2003.

    (Copy Project Interface; Options I chose to create a lean deployment directory...)
    (...And the mysterious warning)

Browsing Google and various Forums, I was led to believe that my .NET Framework/ASP.NET installs were somehow corrupt, and I would have to reinstall or run the aspnet_regiis.exe utility. This didn't sound right to me. I have functioning 1.1/2.0 apps in my development environment, and was able to execute the Copy Project for other 1.1 projects.

I beat myself up about this a bit, and then finally selected "Yes". VS.NET went ahead and built the deployment directory as specified, but not before presenting me with the following popup:

This prompt was familiar to me; it's what you see when an application does not have anonymous access enabled in IIS. Enabling anonymous access eliminated the original VS.NET error!

Hopefully this tip will save someone troubleshooting time or scalp hair.

Monday, May 21, 2007

Overriding Web.config Using Location Tag

Let's say you have a web application with several static configuration settings stored in the <appsettings> collection. Then let's say you want one module of your application to behave differently, i.e. a different set of Application Settings should apply.

Use the <location> tag in web.config to describe the settings for folders within the application.

Web.config Snippet
I have a web application set up in c:\inetpub\myapp, aka http://localhost/myapp. A snippet from web.config is illustrated here:

The application reads settings from the collection by default, unless the request is made to the Test folder.

MyApp Settings

The following screen shot illustrates the default behavior:

Test Settings

And here are the overrides, using the same test page under the /Test folder:
Piece of cake, huh? For the brief testconfig.aspx source code, visit the following link.

Friday, May 18, 2007

Developers: Friendly HTTP Errors can be Unfriendly

Be sure to disable friendly http errors when developing web applications.

These "friendly" errors can mask a problem when troubleshooting. This is prevalent in ASP applications. The following app is missing a virtual directory, and the client has friendly errors turned on:

That doesn't really tell you much, does it? Now here's what we get with the option turned off:

That's a little more informative (minus the proprietary details), isn't it? Keep it unfriendly!

Wednesday, May 16, 2007

Get To Know Your Hosts File

What is the Hosts File
It is a plain text file located within your system directory. It has no file extension.

  1. Windows 2000 - c:\winnt\system32\drivers\etc\hosts
  2. Windows XP, 2003 - c:\windows\system32\drivers\etc\hosts
  3. You'll find equivalent files in other OS's (e.g. Unix)
What Does it Do?
Your Hosts file overrides DNS, forcing HTTP requests to route the way you specify.

Why is it Useful?
There are all kinds of uses for Hosts, depending on your problem at hand. Here are some examples:

  1. You set up numerous IIS sites (e.g. in a development environment (server OS), and want to test them via a browswer.
  2. You are developing a single site with multiple behaviors based on domain name (e.g. has a blue background; has a red background). You want to be able to test these behaviors.
  3. Your are troubleshooting your company's load-balanced server farm. Customers are complaining about a site/application, but you are having difficulty recreating. If the problem is isolated to a specific server, you can force http requests to each server in the farm, provided you have the list of IP addresses.
  4. You want to block various ad/banner nuisances.
Brief Example
You are developing a fictional site to IIS, running Windows XP. Call this site
  1. Open c:\windows\system32\drivers\etc\hosts in a text editor
  2. Add the following line:
  4. Save the file.
  5. Close any open internet browsers.
  6. Open a browser and go to

The request will open the home page of your default web site. If you've never used Hosts, give it a shot!

Monday, May 14, 2007

DNS For Dummies

If you are like me, application-heavy and network-light, then DNS is a relative mystery to you. A friend (network guy) gave me the following high level explanation.

You type and enter an address into your browser, e.g.

The first thing that happens is your computer asks your ISP's (e.g. AT&T's) DNS server (1) "do you know the IP address for this website?" If it does, it will tell your computer what it is, and you connect directly to the Website Server (3).

If your ISP's DNS server doesn't know, it will ask (in a roundabout way) the website owner’s DNS server for the IP address(2). Then it connects to the website server (3).

Once your ISP's DNS server knows the IP address, it keeps it in cache so it doesn't have to ask again, thereby making the connection quicker on subsequent requests. This is why you sometimes experience a slow page load when visiting a website for the first time, but then witness quicker connection on subsequent visits.

There are more "nuts and bolts" to DNS, but this is an intuitive picture for people who can't work with DNS directly.

Thursday, May 3, 2007

Installing a Windows Service


A few weeks ago I wrote a brief entry on Lewis Moten's Visual SourceSafe Journal Monitor. This tool runs as a windows service, polling the specified journal.txt every few minutes and updating a data source with the latest VSS changes.

This got me interested in windows services in general and how you set them up using VS.NET. Here is a link to another CodeProject article focusing on setting up a Windows Service project. It details:

  1. How to set up and build a simple Windows Service project.
  2. How to create a setup package (.msi) to install the Windows service.

I work for an organization where the administrators will not accept an .msi package. They want more visibility into what exactly you are trying to do to their production machines, since they are ultimately responsible for keeping them up and running.

Here's how you can install/uninstall a windows service .exe using VBScript .

Monday, April 30, 2007

Our Vendor Skipped the Gym to Help Us Out

My company outsourced its data center. Now the most trivial task is like resolving a bad cable bill.

As part of the transition to a "cheaper" solution, we moved a bunch of our web servers from our data centers (which were once run by in-house employees with domain knowledge) to the vendors. Lo and behold, stuff stopped working, particularly applications' ability to connect and perform database operations.

So that's all the back story. Here was the kicker...this dba for the vendor wanted us to know that she skipped the gym to get our products, that our customers rely on, up and running again.

Never ever tell a customer that you are really put out by their request. Some analogies:

    "I'll have you know I'm missing my high colonic to make you this bagel"
    "I skipped my nap to perform this hysterectomy"

Friday, April 27, 2007

Implementing a "Click Through" in Classic ASP

To simulate a client request for a given url, use Javascript that automatically fires during the test page load event.
To test that this "referral" script works, point the "referrer" to a handy ServerVariables display page.

Both the "referrer" (click.asp) and the "target" (servervars.asp) are illustrated here.
Here is a screen shot of the resulting HTTP_REFERER display page (servervars.asp)

Here's How you Force SSL in Creaky Old ASP

Say you have a Classic ASP site or application where you want to force a secure (SSL) connection.

Use the ASP ServerVariables collection to check the current connection, then redirect appropriately.

Copy/Paste the following into a text file and name it ForceSSL.asp:


If UCase(Request.ServerVariables("HTTPS")) = "OFF" Then
'''get page
    sRedirect = "https://" & Request.ServerVariables("SERVER_NAME") &
    Request.ServerVariables("PATH_INFO") & "?" & Request.Querystring
    Response.Redirect sRedirect
End If


For each page in the site/application, add a server-side include that looks like this:

<!--#include virtual="/ForceSSL.asp"-->

AG, hope this helps you out. I'm probably weeks too late.

Tuesday, April 24, 2007

Tuesday, April 17, 2007

Web.config - Using an External File

You may find it necessary to separately manage a particular section of your web application's configuration.

Say, for instance, you want to manage a single code base (one web.config file) but you want the application to behave differently on different servers (development, QA, production).

ASP.NET 2.0 allows you to modularize a configuration section using the configSource attribute. The following is an illustrative example:

MyApp has a web.config file that specifies an external source for the appSettings section:

You can store the external file, appSettings.config, anywhere within the application, provided the configSource attribute must specifies a virtual path. Sorry, physical paths or paths outside the application are prohibited.

Getting back to the example, appSettings.config contains a well-formed <appSettings> section:

That's all there is to it! To test the retrieval of these settings, here is a simple .aspx form, testconfig.aspx:

Finally, here's what the output looks like when you visit http://localhost/myapp/testconfig.aspx:

Link to Cut-and-paste-friendly code

Monday, April 16, 2007


Check out the following . I was able to last just over 21 seconds. How about you?

Google Driving Directions

Aunt Jojo showed me this tidbit:

  1. Go to Google and select "Maps"
  2. Select "Get Directions"
  3. Get directions from "New York, New York" to "London, England" or other major European city.
  4. Read the instructions very carefully.

Friday, April 13, 2007

Aspnet_regiis -c

Have you ever seen the following ASP.NET client-side error?

It is most common in production environments that host multiple IIS sites and applications.

If your ASP.NET 1.1 application implements dynamic validation controls, it is dependent on the existence of an /aspnet_client directory. This directory must be a child folder of the site's home directory. Here is a sample scenario:

  1. We have a site on a production server,
  2. serves web pages residing on the server's file system at c:\abc. This is the home directory.
  3. I have an application hosted at
  4. My application serves web forms residing at c:\myapps\newapp

My "newapp", which uses validation controls, depends on the existence of c:\abc\aspnet_client. If the ABC site is managed by someone else (some other department in your company), you may not be comfortable with this dependency! E.G, what if someone managing the site content in ignorantly deletes /aspnet_client, fearing it to be malicious?

Furthermore, while /aspnet_client is handled for you in VS.NET, it is not automatically created for new sites added to IIS. So if you are launching a new site and a new ASP.NET 1.1 application, you will have to include a step to build the /aspnet_client directory. This step is:

Aspnet_regiis -c

This creates the /asnet_client folder under EVERY website node in IIS. So you are safe until the next time some fool deletes it or renames it on the shared server.

Alternative to /aspnet_client

You can remove the dependency of your app on the parent root by overriding the location of the ASP.NET client scripts in web.config. First, copy the scripts folder from the parent root (e.g. c:\abc\aspnet_client) to the application root (e.g. c:\myapps\newapp\aspnet_client). For clarity, rename the folder from aspnet_client to aspnet_override. Then, set the override in web.config:


    This section is settings to enable client-side validation code.
    <webControls clientScriptsLocation="aspnet_override\\"/>

Now you manage the client scripts yourself!

Monday, April 9, 2007

Aspnet_Regiis - Encrypt/Decrypt Web.config

Encrypting a Configuration Section
IIS/ASP.NET will not serve direct requests to Web.config, which protects possibly sensitive information (e.g. connection strings, email addresses) from the least in theory.

You can further protect web.config information via encryption. Out of the box, the aspnet_regiis.exe utility will encrypt web.config according to your preferences.

Here is a sample <appsettings> section:

Assume that this application runs under http://localhost/myApp, we could run the following command to encrypt:

    aspnet_regiis -pe "appSettings" -app "/myApp"

After which, the <appsettings> section would look like this:

Implementing Code to Retrieve Configuration Settings
What's great is that the code that accesses the configuration settings need not change, e.g.:
    string strGUID = ConfigurationSettings.AppSettings["ROOTGUID"];

...would work before and after encryption.

To decrypt the configuration settings, just substitute a "-pd" switch for "-pe":

    aspnet_regiis -pd "appSettings" -app "/myApp"

...Finally, I came across a good article about handling this encryption/decryption programmatically (e.g. via an ASP.NET page or a Console App). Here's the 4gfr link.

Friday, April 6, 2007

Intro to Aspnet_Regiis.exe

Aspnet_regiis.exe is a command line utility that installs ASP.NET features to Internet Information Server (IIS). You find it in your c:\windows\\framework\v#.### directory. Installable components include such things as:

  • An ISAPI Filter - used by IIS to direct incoming requests to the appropriate
    runtime engine based on the extension (e.g. .asp, .aspx)
  • Script Maps - configuration settings in each IIS node that specify how various extensions are processed (see Figure 1).

  • Client Validation Scripts - /aspnet_client Javascripts that provide dynamic behavior to web form validation controls (see Figure 2)

  • Options for encrypting configuration (*.config) files.

  • etc

(figure 1 - aspx script mapping)

(figure 2 - client validation scripts)

Very carefully :). Read the various options by typing "aspnet_regiis.exe -?". Run them on a development server to get familiar with them, backing up the IIS metabase appropriately.

CAUTION: Using the "-i" Switch
If you run the utility with "-i", you will install the ASP.NET version specified by the utility's parent directory (e.g. "v1.1.4322"). This includes the ISAPI filter and script maps for all nodes in the IIS tree...

Think about that, because it could get you in to trouble, say, if you are running the utility from the v2.0.50727 directory of a web server that currently runs a bunch of older 1.1 applications. Those applications will be forced to the 2.0 version of the processing engine (aspnet_isapi.dll) and could very well stop working. Better to leave well enough alone!

To leave existing scripts as-is, use the combination switch "-ir". Per the documentation, this installs the specified version of ASP.NET without updating script maps. Then to set assign applications to the appropriate version, set them manually in IIS or use script explained in this earlier blog.

Wednesday, April 4, 2007

VBScript Fun - Create a File System Directory

Okay, I was stretching for something to write today. So I thought I'd include an entry on my good friend, FileSystemObject, which has been my "go-to" on many occasions.

So, an example...

Say you want to automate the creation of a file system hierarchy, with folders that don't currently exist, and branch pretty deeply. Using the following function, you can pass a long path and the File System Object will create each layer:

makeDirectory "c:\diablopup\testing\a"
  • '''''''''''''''''''''''''''''''''''''''''''''''''''

  • ' This method is responsible for creating a directory

  • ' The directory can be several layers deep, and if the

  • ' parent directories don't exist, it creates them.

  • ' If the directory already exists, it is left alone

  • ''''''''''''''''''''''''''''''''''''''''''''''''

  • sub makeDirectory (newPath)
      Dim myArray,length,count,path,outputFileObject
        Set outputfileObject = CreateObject("Scripting.FileSystemObject")
          if outputfileObject.FolderExists(newPath) then
        • wscript.echo "Dir: "&newPath&" already exists <-- makeDirectory() "

        • exit sub

          end if
            path = ""
            count = 0
            myArray = split(newPath, "\")
            length = ubound(myArray)

            while count <= length
          • path = path + myArray(count) + "\"
          • count = count + 1
          • if not outputfileObject.FolderExists(path) then
            • outputfileObject.CreateFolder(path)
          • end if
              wscript.echo "Created Dir: "&newPath&" <-- makeDirectory() "
              end sub

            Tuesday, April 3, 2007

            VB.NET - Visual SourceSafe Journal Monitor Service

            During an interview with a prospective employee last week, we got to talking about Visual SourceSafe.

            He remarked that while VSS provides solid version control facilities, the reporting was lacking. How do you get a snapshot of the VSS activity for a time period, or for a person?

            VSS is project-centric, providing history for a project. If you want info on activity for a time period or a person, you are left to eyeball the journal (text file), provided you have one configured.

            This guy brought up a good point, and it was clear from the discussion that he was used to working with the tool. But I got to thinking. The VSS Journal is a list of entries like the following:

            Version: 10
            User: diablopup Date: 4/03/07 Time: 4:10p
            Checked in

            Couldn't we parse this file into a normalized database, indexed, say, by VSS Path, User, DateTime? Then I thought, I bet someone has done this before. A little Google research, and...Thank you, Lewis Moten!

            He created this neat Windows Service. Not only does it parse the journal data into a database, it keeps the database up to date by polling the journal file on a regular basis.

            You can also configure it to send you notifications as a project is updated, or even to send you an instant message from MSN Messenger (I found this feature distracting, and removed it). Team Foundation Server is supposed to have these features built-in, but you (like me) may not be using it at your company for awhile.

            Monday, April 2, 2007

            C# Reflection Example - Debug or Release?

            Use .NET reflection to gather information about the current application.

            For example, to verify whether the current application was compiled in release or debug mode:

            1. Inspect the Attributes collection of the Assembly object specified by a dll path.
            2. Find the Attribute of type DebuggableAttribute.
            3. Check that Attribute's IsJITTrackingEnabled property.

            Here is a link to the code.

            I used it to display the compile mode in an About screen:

            Friday, March 30, 2007

            C# Class for Routine Registry Lookups

            Say you need to store a lot of application configuration data in the system registry. Why would you need to do this, when you can use various .NET .config files?

            The idea may seem kind of archaic, but you may work with web servers that have been around a long time, where legacy ASP and ASP.NET applications cohabitate. Different applications that live on these servers were probably written by different groups separate by geography and time. Standards become important in such an environment! Registry use is not an uncommon standard.

            Okay, that's the long scenario explanation... Should you need to make repeated trips to a registry key or its subkeys, here is a C# class to facilitate. The functions make use of the static Microsoft.Win32.Registry object.

            Example of usage:

            Please Note: to read registry settings successfully, the authenticated user of the ASP.NET application must have read access to the specified registry key.

            Thursday, March 29, 2007

            CDOSYS/CDOSYS - an Email Function that Works with Either

            Say you have an extremely OLD classic ASP application, written circa 1999. Your company's CIO has mandated that all applications be migrated to new (Windows 2003/IIS6) servers.

            Stuff that worked in IIS4-5 doesn't always work in IIS6. Emailing using the old CDONTS.NewMail object is trouble.

            To prepare for the migration, you want a single code base that works on the old and the new server. The following functions , based on the "SERVER_SOFTWARE" server variable, will help.

            Wednesday, March 28, 2007

            Internet Explorer Web Controls - Simple TreeView Implementation

            Wiring up a TreeView component can be tricky the first time, particularly if you've never seen it done. The following is a simple example of a Treeview hierarchy with multiple, external XML sources.

            Code moved to Live Spaces blog for readability.
            Here is the result:

            Tuesday, March 27, 2007

            IT Jargon - "Time Stamp"

            Time Stamp - to create some meaningless electronic record, usually an email, to prove that you showed up to work today. The record does not represent any real artifact of work or problem solved; it simply proves to anyone keeping track that you bothered to log in. Example of a meaningless time stamp-type message:

            Wow, that was a helpful nugget! We sure are lucky to have this guy on our team. He's always on the lookout for new developments.

            "Time Stamping" is a behavior common in matrixed, distributed organizations. E.G., you work for a technical department with say, 100 "resources", 1-2 directors who actually sign off on budgets and merit increases, and many project managers with some accountability and little authority.

            For the "resources" in such an organization, it can be easy to hide and live by "time stamping" while working from home, shopping online and engaging in self-abuse. Look around, you probably know some "Time Stampers". Or maybe you are one. If so, good for you! Hopefully you are saving the money you are stealing, because the free ride won't last forever.

            Monday, March 26, 2007

            C# Console App to Update Machine.config

            I store proprietary information in our company's web servers' Machine.config's in order to manipulate the behavior of multiple applications. E.G., an appSetting determines whether the current machine is used for shared development, integration, pre-production testing, or production.

            Unfortunately, I am not an administrator on the servers. No, we have outsourced that privilege to a vendor without accountability. Sound like an accident waiting to happen? That's a story for another day...

            Anyway I can send a ticket to their help desk to have someone add the <appsettings> section if it doesn't exist, and then add my "Environment" key. But how do I trust that the person who picks up the ticket knows the first thing about where the appSettings section goes within Machine.config or its case-sensitive nature? I CAN'T.

            The following is code for a console app that will update Machine.config according to your command line arguments:

            Code snippet moved to my Windows Live Spaces Blog, for better readability.

            Friday, March 23, 2007

            IE Web Controls - Tree View - Client Scripts

            The IEWC Tree View component is useful if you are writing an ASP.NET 1.1 application and need to display a relatively large collapsible hierarchy (tree structure).

            During installation (addressed in an earlier blog), a "/webctrl_client" directory is added to your default web site (c:\inetpub\wwwroot\webctrl_client). By default, the treeview component uses this location to reference the client-side scripts for image rendering and click behavior.

            If you have a shared server environment with multiple web sites (Win2k Server or Win2k3 server), you have to copy this webctrl_client folder to the home directories of each site using the controls.

            Alternatively, you can define a custom location in your web.config. This would allow you to set up a virtual directory and maintain the webctrl_client stuff in a SINGLE PLACE.

            Here is close to the syntax to add to your web.config, directly within the section.

            <section name="MicrosoftWebControls" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.3300.0,Culture=neutral,PublicKeyToken=b77a5c561934e089"/>

            <add key="CommonFiles" value="/" />

            Wednesday, March 21, 2007

            Random Google Tip

            The following Google Query will search for browsable directories on the internet containing music:

            -inurl (htm|html|php) intitle:"index of" +"last modified" +"parent directory" +description +size +(wmamp3) "Beatles"

            If you have the time or inclination, this could be useful. Thanks to straight-A for pointing this out.


            Sorting Arrays in VBScript - Part 2

            Yesterday, I included a function to sort an array of numbers or strings. The following is a minor spin on that function, sorting an array of OBJECTS by their .name attribute. Pretty much all Microsoft-related objects have this name attribute. So you could sort an array of website objects, virtual directory objects, file objects, etc.

            Hope this helps somebody!

            ' SortObjectArrayByName - sort an array of objects by their name attributes
            ' arrObj - incoming array of unsorted objects
            function SortObjectArrayByName(arrObj)
            dim i, j, temp
            dim name0, name1, obj

            for i = UBound(arrObj) - 1 To 0 Step -1
            for j= 0 to i
            set obj = arrObj(j)
            name0 =
            set obj = arrObj(j+1)
            name1 = obj.Name
            if name0 > name1 then
            set temp = arrObj(j+1)
            set arrObj(j+1) = arrObj(j)
            set arrObj(j) = temp
            end if
            SortObjectArrayByName = arrObj
            end function

            Tuesday, March 20, 2007

            Sorting Arrays in VBScript

            Here's a simple function to sort your simple array. Hope it makes your life simpler.

            '****************************************************************************************** ' SortArray - sort a string or numeric array
            '****************************************************************************************** function SortArray(arrShort)
            dim i, j, temp
            for i = UBound(arrShort) - 1 To 0 Step -1
            for j= 0 to i
            if arrShort(j)>arrShort(j+1) then
            end if
            SortArray = arrShort
            end function

            Internet Explorer Web Controls - Installation

            Here is an obscure, simple install package for the IE Web Controls, useful in ASP.NET 1.1:


            It mentions that the controls are specifically for Content Management Server. Don't be fooled. They are the same controls. The CMS team seems to have taken it upon themselves to create a more user friendly install package.

            Programmatic IIS Administration - Selecting a Virtual Directory

            This is a followup to an earlier post, Selecting a Site. The following function will return a virtual directory object, which you can then manipulate (set Directory Security options, ASP.NET version, etc.)

            ' This sub will pass back a VirtualDirectory from a given Website Name, Virtual Directory Child 'Name
            ' Paramters: WebSite = Website Name
            ' VirDirName = Virtual Directory Name
            function GetVirtualDirectory(WebSite,VirDirName)

            dim adspath,rootobj,WebSiteObj

            set WebSiteObj=GetWebSiteByName(WebSite)
            set rootObj=getObject(WebSiteObj.adsPath&"/root")


            set GetVirtualDirectory=getObject(adspath&"/"&VirDirName)

            end function

            Monday, March 19, 2007

            Assign an Application Pool using VBScript

            The following script will assign a given IIS object (site or virtual directory) to an existing application pool.

            Note that it relies on a helper function to check if the pool exists.

            It also makes sure that the current machine is Win2003 -- you can't specify pools in prior OS's. This OS check function was detailed in a previous blog

            '****************************************************************************************** ' Name: SetAppPool
            ' Description: Assign the IIS Object to an Application Pool (IIS 6 only)
            ' Inputs: ObjApp (IIS Object), strAppPool (Pool to assign to)
            sub SetAppPool(ObjApp, strAppPool)
            if instr(GetOS_Remote("."), "2K3") <> 0 then
            if AppPoolExists(strAppPool) then
            ObjApp.AppPoolId = strAppPool
            logmsg "Set App Pool to " & strAppPool
            logmsg "Error: App Pool " & strAppPool & " Not Found"
            end if
            logmsg "Skip app pool setting; not a 2003 server"
            end if
            end sub

            ' Name: AppPoolExists
            ' Description: See if the application pool exists (IIS 6 only)
            ' Inputs: strAppPool
            function AppPoolExists(strAppPool)
            dim objPool
            on error resume next
            Set objPool = GetObject("IIS://localhost/w3svc/AppPools/" & strAppPool)
            if err.number <> 0 then
            AppPoolExists = false
            AppPoolExists = true
            end if
            end function

            Friday, March 16, 2007

            Setting ASP.NET Version via Script

            Say you have a web server running multiple versions of ASP.NET. Various applications, for better or for worse, depend on a specific version of ASP.NET (e.g. it works under 1.1; throws errors under 2.0).

            Here is a function for setting the version using ADSI automation:

            Code snippet moved to a dedicated blog for readability

            CDONTS, CDOSys, and a Blank Email Address

            Anyone who has migrated a legacy ASP application to Win2003/IIS6 is familiar with CDONTS and CDOSys. Code that sends email via CDONTS stops working in W2k3/IIS6 because there is no CDONTS.dll!

            Code must be migrated from using CDONTS.NewMail to CDOSys.Message. Required changes are fairly straightforward.

            Here's a subtle difference: your ASP application under CDONTS will not visibly fail if you provide an empty string "" for the email address. Rather, the email message will fall into your ISP's bad mail bin. CDOSys, on the other hand, will throw an error, and the application will quit on the end user if the error is unhandled.

            Here are proof of concept scripts to show you the variance. You can run these from a command prompt:

            CDONTS(Won't fail)
            wscript.echo "creating cdonts object!"
            dim mailObj : set mailObj = CreateObject ("CDONTS.NewMail")
            wscript.echo "created"
            mailObj.From = ""
            mailObj.To = ""
            mailObj.Subject = "hallo"
            mailObj.Body = "hello there"
            mailObj.BodyFormat = 1
            mailObj.MailFormat = 0
            wscript.echo "mail sent, supposedly"
            set mailObj = Nothing

            CDOSys(Will Fail)
            dim objCDOMailer : Set objCDOMailer = CreateObject("CDO.Message")
            objCDOMailer.To = ""
            objCDOMailer.From = ""
            objCDOMailer.Subject = "hallo"
            objCDOMailer.TextBody = "hello there"
            objCDOMailer.Send set
            wscript.echo "Message sent successfully!"

            Thursday, March 15, 2007

            Apologies for Code Snippet Formatting

            Readability called, and wanted to know why she wasn't invited to this blog.

            I clearly haven't mastered the posting editor. I hope to improve, or find a blog host with a better editor.

            Query a Machine's OS Using WMI

            Say you need to automatically configure a bunch of servers with varying operating systems. The configuration you specify will vary by OS.

            For example, you can't set up an IIS Application Pool on Windows 2000, which does not run IIS 6, but you still want to install web applications and manage a similar IIS tree.

            Here is a function that returns an OS indicator. You can query a remote machine's OS, provided you have administrative access. To query the local machine, use "." for the machine argument.

            ' Get System OS from a Remote Machine
            Function GetOS_Remote(strMachine)
            'WMI is required for this script to function

            Dim strComputer, strWMIOS

            Dim objWmiService : Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strMachine &

            Dim strOsQuery : strOsQuery = "Select * from

            Dim colOperatingSystems : Set colOperatingSystems =

            Dim objOs

            Dim strOsVer
            For Each objOs in colOperatingSystems

            strWmios = objOs.Caption & " " & objOs.Version


            Select Case True

            'Add more info to the 98 and 95 to get the specific version. i.e. 98SE 95 a,b,or c

            Case InStr(strWmiOS, "2000 Server") > 1 : GetOS_Remote = "2KSRV"

            Case InStr(strWmiOS, "2003, Standard") > 1 : GetOS_Remote = "2K3SRV"

            Case InStr(strWmiOS, "2003, Enterprise") > 1 : GetOS_Remote = "2K3ENTSRV"

            Case InStr(strWmiOS, "2000 Advanced Server") > 1 : GetOS_Remote = "2KADVSRV"

            Case InStr(strWmiOS, "Windows NT") > 1 : GetOS_Remote = "NT4"

            Case InStr(strWmiOS, "Windows 2000") > 1 : GetOS_Remote = "W2K"

            Case InStr(strWmiOS, "Windows XP") > 1 : GetOS_Remote = "WXP"

            Case Else : GetOS_Remote = "Unknown"

            End Select

            End Function

            Wednesday, March 14, 2007

            Programmatic IIS Administration - Selecting a Site

            Configuring a web server can be complicated, particularly if it is running multiple web sites, with multiple virtual directories under each site. Such a complex IIS tree requires many, many mouse clicks in order to configure according to specifications.

            And what happens if the server catches on fire? It may be a good idea to script the configuration. VBScript and the IIS ADSI objects offer a multitude of possibilities.

            Here is a simple VBscript function for selecting a site by name (which you can then configure with proper directory security, isolation level, host headers, etc...)

            Function GetWebSiteByName(WebSiteName)
            dim rootObj,count,website
            set rootObj=GetObject("IIS://LocalHost/W3SVC")

            for each website in rootObj
            if LCase(website.class) = LCase("IIsWebServer") then
            if LCase(website.ServerComment)=LCase(WebSiteName) then
            set GetWebSiteByName=website
            exit function
            end if
            end if

            end Function

            Refer back for more Automated IIS Administration examples, using low-tech script :)

            Running your Web Application under the Wrong ASP.NET Version?

            • You've built an ASP.NET 2.0 app in your c:\inetpub\wwwroot directory.
            • The app runs smashingly in VS.NET 2005 and when you run it from http://localhost/yourapp .
            • When you upload it to your host or deploy it to your company's production server, it doesn't work!

            Does this sound like a problem you've encountered? It's a familiar scenario.

            Your application, built to ASP.NET 2.0, may be running under ASP.NET 1.1 or earlier. Symptoms include an inability for the ASP.NET engine to properly parse your web.config file. Or more specifically, yellow screens that include statements like:

            • Parser Error Message: Unrecognized attribute 'xmlns'.
            • Parser Error Message: Unrecognized configuration section "xhtmlconformance"

            I would include the yellow screens, but the blog host won't upload my gifs. More later.