Type-Safe Enum Strings in .NET

One thing that has always bothered me in .NET is the inability to create a type-safe set of string constants like an enum. I would like to create a type such as the following:

public enum StoredProcedure : string
{
DeleteConsumer = "DeleteConsumer",
EditConsumer = "EditConsumer",
GetConsumer = "GetConsumer"
}

This would be incredibly useful for those situations where you are passing constant strings to a given method and you would like to limit the options that are passed to a finite set of options that can be detected through a type-safe check during compile time.

public void ExecuteDataSet(StoredProcedures storedProcedure)
{
SqlCommand command = new SqlCommand();
command.CommandType = CommandType.StoredProcedure;
command.CommandText = storedProcedure.ToString();
}

Unfortunately, a simple constant does not provide type-safe protection for the method call. If a developer is not aware of the pattern, they may end up sending in a literal string of their choosing. So, instead you end up with the following:

public void ExecuteDataSet(string storedProcedure)
{
SqlCommand command = new SqlCommand();
command.CommandType = CommandType.StoredProcedure;
command.CommandText = storedProcedure.ToString();
}

After working at a heterogeneous shop, I learned that Java has been creating their own type-safe string enum classes for solving this situation for years before the formal enum type was added to the 1.5 release of the Java Runtime.

The example below shows how a typical Java developer would implement this concept in Java syntax.

public final class Color {

private String name;

private Color(String name) {
this.name = name;
}

public String toString() {
return this.id;
}

public static final Color RED = new Color("Red");
public static final Color GREEN = new Color("Green");
public static final Color BLUE = new Color("Blue");
}

The basic idea is simple:

1. Define a class representing a single element of the enumerated type

2. Don't provide any public constructors for it.

3. Provide public static final fields, one for each constant in the enumerated type.

Because there is no way for clients to create objects of the type, there will never be any objects of the type besides those exported via the public static final fields.

In order to make this easier to use within .NET, I create an abstract base type, StringConstantBase, that allows a developer to quickly create the functionality above plus some other goodies such as GetNames(), CompareTo(), Equals(), GetHashCode(), and the == and != operators for comparison to string literals.

In order to use the code, you merely define your class as follows:

public class StoredProcedures : StringConstantBase
{
public static readonly StoredProcedures GetConsumer = new StoredProcedures("GetConsumer");
public static readonly StoredProcedures EditConsumer = new StoredProcedures("EditConsumer");
public static readonly StoredProcedures DeleteConsumer = new StoredProcedures("DeleteConsumer");

private StoredProcedures(string name) : base(name){}

}

The only part that does not work (this is the same for the Java version) is that it cannot be used in switch...case statements. Those require the use of an underlying integral type which is not present. Instead, you should use the if...else if construct to perform the same logic.

If you are interested in using the StringConstantBase class for your own code, you can download my Visual Studio 2008 project from here. In addition to the class, I have included a unit test project to include my assumptions on its use.

I hope this helps someone out there...

Turning on Intellisense with Visual Studio 2008

For whatever reason, when I was using Visual Studio 2008 this morning, I noticed that intellisense was not working.  Whenever I typed the period at the end of an object reference, no list of available methods and their associated parameters was made visible as a drop-down. 

I know that I am "man" enough to work without it, but I have come to really enjoy the productivity I get using intellisense - especially when learning a new API.

So, after exploring a bit, I found the settings and am documenting it here, so I don't forget for future reference.

1.  Click on Tools/Options in the upper-menu.

image

2.  Under Text Editor/All Languages navigate to the Statement Completion section at the top of the dialog and check the appropriate settings

image 

There are 3 settings with the following explanation:

  • Auto list members - this is essential for intellisense to begin working.
  • Hide Advanced members - this will allow you to hide those properties, methods, and events that are not often used.
  • Parameter information - by default the auto list members only displays the name of the property, event, or method.  You must have this option checked in order to display the actual parameter information.

I hope this was helpful...

Alessio's In Westlake Village, CA

Tonight my manager and I are going to eat at Alessio's in Westlake Village, CA with a representative from IBM.  I just wanted to add this post as a reminder of the restaurant location.  I'm sure it will be very nice!

I have placed a map of the directions from the Simi Valley office of Countrywide (2900 Madera Road) to the restaurant below for future reference.


View Larger Map

Below is the actual location for the restaurant close up.


View Larger Map

Google for App Domains - Family Site

My family and I are contemplating shutting down our existing family site at http://www.meinershagen.net/community and actually setting up shop with Google for App Domains.  I am so blown away with the services that Google is offering for free (email, calendar, photos, pages, groups, blogs, docs, etc.) that I can't justify paying to host my own site anymore.

Have any of you had experience yet using the Google for App Domains?  If so, what are some of the gotchas that you ran into when starting to use the service?  Thanks in advance for any tips you have...

New SiteAvailabilityHttpModule - Based on Client IP Address

As part of my company’s Technical Council, we are working on defining our process for promoting code from one environment to the next.  One of the items we wanted to standardize across our enterprise was how we stop a site during a promotion. 

ASP.NET 2.0 has a nice feature for shutting down a site called App Offline.  As Scott Guthrie from Microsoft puts it, “the way [App Offline] works is that you place this file in the root of the application.  When ASP.NET sees it, it will shut-down the app-domain for the application (and not restart it for requests) and instead send back the contents of the app_offline.htm file in response to all new dynamic requests for the application.  When you are done updating the site, just delete the file and it will come back online.”  You can find more out about this technique from the original blog entry here.

Unfortunately, our requirements were a bit more complicated than was intended with the app_offline.htm.  First, most of our applications were written with the 1.1 framework, so this built-in functionality was not available for our use.  In addition, we wanted the ability for testers to be able to validate the site once the changes had been made.  However, we didn’t want to have to bring the site back up in order to do that.

As I was looking on line, I found another option called the SiteAvailabilityHttpModule.  This module allowed for the site to be shut down by merely configuring an HttpModule within the web.config.  In the Init() event, the module subscribes to the PostAuthorizeRequest event.  Within the event handler, the system determines whether or not the request occurred during an accepted time frame and whether or not the requesting user belonged to the administrator role. 

We didn’t need either of those features for our deployment.  Instead of using a role-based mechanism for determining a user’s access, we wanted to base access on a configured list of client IP addresses.  As a result, we didn’t need to wait until the PostAuthorizeRequest event – we could check these aspects within the first event – BeginRequest instead.  The code is listed below.

void context_BeginRequest(object sender, EventArgs e)

{

     string ext = Path.GetExtension(HttpContext.Current.Request.Path).ToLower();             

     if(ext == ".aspx")

     {

          if (this.IsEnabled)

          {

               if (!IsClientIPValid())

               {

                    HttpContext.Current.RewritePath("~/SiteUnavailable.htm");

               }

          }

     }

}

Notice that you must place a SiteUnavailable.htm file at the root of the site in order to display content if the user’s client IP address does not match one that is configured in the web.config.  You can find the current release for this component here.