10.20.2006

Generic Null Handling Class for .Net 2.0

Null conversions are a real pain. Nullable types in the 2.0 framework are a great addition, but fall a bit short in my mind. They don't handle DBNull values coming out of the database, so that leaves you with more null conversion work to do. For example:

// Wish these would work and do the null conversion for me
// That would just be too good to be true, wouldn't it?
int? i = DBNull.Value;
DateTime myDate = DBNull.Value ?? DateTime.Now;

I find that I typically need to convert the data coming out of the database to a .Net value type. If it's a nullable field in the database, I can implement it in the application with a nullable type, a default value, or the old MinValue trick. I'm usually doing some sort of if-then logic to pull the actual value or supply a default if the value is DBNull.

For example, in .Net 1.1, I would typically use the MinValue to represent null. DateTime.MinValue for example would represent a null date value. In .Net 2.0, I can use the same method, or I can create a nullable DateTime construct and set a null value with some code like this:

// Code to check for null integer value and default null values
int? managerID1 = (reader["MANAGER_ID"] != DBNull.Value) ? (int?) reader["MANAGER_ID"] : null;
int managerID2 = (reader["MANAGER_ID"] != DBNull.Value) ? (int) reader["MANAGER_ID"] : Int32.MinValue;
int managerID3 = (reader["MANAGER_ID"] != DBNull.Value) ? (int) reader["MANAGER_ID"] : 0;

// Date Sample
DateTime? hireDate1 = (reader["HIRE_DATE"] != DBNull.Value) ? (DateTime?) reader["HIRE_DATE"] : null;
DateTime hireDate2 = (reader["HIRE_DATE"] != DBNull.Value) ? (DateTime) reader["HIRE_DATE"] : DateTime.MinValue;
DateTime hireDate3 = (reader["HIRE_DATE"] != DBNull.Value) ? (DateTime) reader["HIRE_DATE"] : DateTime.Now;

In my mind, it's a lot of repetitive code. So I've used C# generics to create a class called NullConvert. I use it to convert null and DBNull values to a default value. It works with all datatypes I've run accross, handles conversions between datatypes intrincally, and even handles conversions from string, int, or null values to enumerations. Full code for the class is listed at the bottom of this post. Here's some sample usage:

// Sample usage of NullConvert class using generics  
// Shows conversion to both nullable and non-nullable types
int? managerID1 = NullConvert.IsNull<int?>(reader["MANAGER_ID"], null);
int managerID2 = NullConvert.IsNull<int>(reader["MANAGER_ID"], Int32.MinValue);
int managerID3 = NullConvert.IsNull<int>(reader["MANAGER_ID"], 0);

// String sample
string managerName1 = NullConvert.IsNull<string>(reader["MANAGER_NAME"], null);
string managerName2 = NullConvert.IsNull<string>(reader["MANAGER_NAME"], Int32.MinValue);
string managerName3 = NullConvert.IsNull<string>(reader["MANAGER_NAME"], 0);

// Date sample
DateTime? hireDate1 = NullConvert.IsNull<DateTime?>(reader["HIRE_DATE"], null);
DateTime hireDate2 = NullConvert.IsNull<
string>(reader["HIRE_DATE"], DateTime.MinValue);
DateTime hireDate3 = NullConvert.IsNull<
string>(reader["HIRE_DATE"], DateTime.Now);

// Sample of data converstion.  SQL Decimal is automatically converted to
// decimal, double, or other numeric data types
decimal hourlyRate1 = NullConvert.IsNull<decimal?>(reader["HOURLY_RATE"], null);
double hourlyRate2 = NullConvert.IsNull<double?>(reader["HOURLY_RATE"], null);
float hourlyRate3 = NullConvert.IsNull<float?>(reader["HOURLY_RATE"], null);

// Sample of enumeration conversion.  
// Handles conversion of textual or numeric representation and null values
// Handles both nullable and non-nullable enumeration types
enum EmployeeType {Employee = 1, Manager = 2, Contractor = 3};
ContactType? contactType1 = NullConvert.IsNull<ContactType?>(reader["CONTACT_TYPE"],
null);
ContactType contactType2 = NullConvert.IsNull<ContactType>(reader["CONTACT_TYPE"], ContactType.Employee);
ContactType contactType2 = NullConvert.IsNull<ContactType>("Manager", ContactType.Employee);
ContactType contactType2 = NullConvert.IsNull<ContactType>(2, ContactType.Employee);

The class also includes a couple of other useful methods:
  • The NullConvert.ChangeType() method is an extended implementation of the System.Convert.ChangeType() method, designed to handle nullable types and enumerations which are not supported by the standard .Net implementation. Thanks to Peter Johnson for the original code, which can be found on ASP Alliance, I just added support for enumerations by adding a line or two.
  • The NullConvert.SqlNullString() method handles string values being stored in the database. I don't like storing empty strings in my database. If I have an empty string entered by a user, I like to store it as a NULL value in the database. The SqlNullString() method handles this conversion, and also trims the string by default.
Full code for the NullConvert class:
using System;
using System.ComponentModel;

/// <summary>
///
Utility class exposing null handling routines to convert null values coming to
/// and from the database.
/// </summary>
public class NullConvert
{

    #region Constructors

    
// Hide public constructor to implement a singleton pattern
    private NullConvert()
    {
    }

    
static NullConvert()
    {
    }

    #endregion

    #region
Static Methods

    
/// <summary>
    /// Checks a value for a null or DBNull value.  If the value is not null, value is converted
    /// to the type specified. Works on value types, enumerations, and nullable values types.  If
    /// the value is null, the default value is returned.
    /// </summary>
    /// <typeparam name="T">Type expected in return</typeparam>
    /// <param name="value">Value to check and convert as needed</param>
    /// <param name="defaultValue">Default value to return if value is null or DBNull</param>
    /// <returns>Converted value of type specified as T</returns>
    public static T IsNull<T>(object value, T defaultValue)
    {
        
//// Test for nullable types, if we need it later.  This works!
        //Type type = typeof(T);
        //if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
        //{
        //    throw new ApplicationException("Hit it");
        //}

        if (value == null || value == DBNull.Value)
        {
            
return defaultValue;
        }
        
else
        {
            
return (T) NullConvert.ChangeType(value, typeof(T));
        }
    }

    
/// <summary>
    /// Prepares string values for insertion into the database.  Converts value to a string,
    /// trims it (optional), and checks for an empty string.  If String.Empty is the result,
    /// a null string is returned to insert a NULL value into the database.
    /// </summary>
    /// <param name="value">Value to convert</param>
    /// <param name="trimString">Trim the resulting string? Defaults to True</param>
    /// <returns>Resulting string or null string</returns>
    public static string SqlNullString(object value, bool trimString)
    {
        
// Convert value to string
        string result = Convert.ToString(value);

        
// Trim it?
        if (trimString)
        {
            result = result.Trim();
        }

        
// If string is empty, convert it to null
        if (String.IsNullOrEmpty(result))
        {
            
return null;
        }
        
else
        {
            
return result;
        }
    }

    
/// <summary>
    /// Prepares string values for insertion into the database.  Converts value to a string,
    /// trims it (optional,) and checks for an empty string.  If String.Empty is the result,
    /// a null string is returned to insert a NULL value into the database.
    /// </summary>
    /// <param name="value">Value to convert</param>
    /// <returns>Resulting string or null string</returns>
    public static string SqlNullString(object value)
    {
        
return SqlNullString(value, true);
    }

    
/// <summary>
    /// Returns an Object with the specified Type and whose value is equivalent to the specified object (handles nullable types).
    /// </summary>
    /// <param name="value">An Object that implements the IConvertible interface.</param>
    /// <param name="conversionType">The Type to which value is to be converted.</param>
    /// <returns>An object whose Type is conversionType (or conversionType's underlying type if conversionType
    /// is Nullable and whose value is equivalent to value. -or- a null reference, if value is a null
    /// reference and conversionType is not a value type.
    /// </returns>
    /// <remarks>
    /// This method exists as a workaround to System.Convert.ChangeType(Object, Type) which does not handle
    /// nullables as of version 2.0 (2.0.50727.42) of the .NET Framework. The idea is that this method will
    /// be deleted once Convert.ChangeType is updated in a future version of the .NET Framework to handle
    /// nullable types, so we want this to behave as closely to Convert.ChangeType as possible.
    /// This method was written by Peter Johnson at:
    /// http://aspalliance.com/author.aspx?uId=1026.
    /// </remarks>
    public static object ChangeType(object value, Type conversionType)
    {
        
// Note: This if block was taken from Convert.ChangeType as is, and is needed here since we're
        // checking properties on conversionType below.
        if (conversionType == null)
        {
            
throw new ArgumentNullException("conversionType");
        }
// end if


        // If it's not a nullable type, just pass through the parameters to Convert.ChangeType
        if (conversionType.IsGenericType &&
          conversionType.GetGenericTypeDefinition().Equals(
typeof(Nullable<>)))
        {
            
// It's a nullable type, so instead of calling Convert.ChangeType directly which would throw a
            // InvalidCastException (per http://weblogs.asp.net/pjohnson/archive/2006/02/07/437631.aspx),
            // determine what the underlying type is
            // If it's null, it won't convert to the underlying type, but that's fine since nulls don't really
            // have a type--so just return null
            // Note: We only do this check if we're converting to a nullable type, since doing it outside
            // would diverge from Convert.ChangeType's behavior, which throws an InvalidCastException if
            // value is null and conversionType is a value type.
            if (value == null)
            {
                
return null;
            }
// end if

            // It's a nullable type, and not null, so that means it can be converted to its underlying type,
            // so overwrite the passed-in conversion type with this underlying type
            NullableConverter nullableConverter = new NullableConverter(conversionType);
            conversionType = nullableConverter.UnderlyingType;
        }
// end if

        // Is this an enumeration type?
        // Enumeration conversion added to Peter Johnson's original code by Stuart Cox
        if (conversionType.IsEnum)
        {
            
return Enum.Parse(conversionType, value.ToString(), true);
        }
        
else
        {
            
// Now that we've guaranteed conversionType is something Convert.ChangeType can handle (i.e. not a
            // nullable type), pass the call on to Convert.ChangeType
            return Convert.ChangeType(value, conversionType);
        }
    }

    #endregion Static Methods
}

10.16.2006

Put CSS Filters To Work

With a combination of CSS filters like Glow and Shadow, you can get some really nice effects. I had alot of trouble getting CSS filters to work, though, and this post may save you (and me) some time in the future trying to figure it out.

See SSI Developer and Fred's samples for some samples of filters usage. I found nice Shadow filter tutorials on Mandarin Design and A List Apart, two of my favorite design blogs.

Filters should work on img, span, div and font tags. If they don't work immediately, don't be surprised. These filters only work for IE users, and only then if you get it just right. Use of the filters is a bonus, as many users may not see them at all. But the effects can be quite nice (see some shadow and css samples in this post below), especially if you're in a controlled browser environment (intranet apps).

Here's a checklist I found I had to use to get it working. My test browser is Internet Explorer 6.0 running on Windows XP sp2.

1 Check Your DOCTYPE
The DOCTYPE specified for your page has to be right or they will not work (for more information, read the W3C DOCTYPE guidelines). If you have specified a DOCTYPE for HTML 4.1 or XHTML 1.0/1.1, the filters will not work. The HTML 2.0 and HTML 3.2 doc types worked well for me. Try one of these DOCTYPES or remove the DOCTYPE altogether if you can. I also had success with listing multiple DOCTYPE tags, as long as I listed one of these first.

<!-- Use the HTML 3.2 DocType -->
<!
DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<!
-- OR the HTML 2.0 DocType -->
<!
DOCTYPE html PUBLIC "-//IETF//DTD HTML 2.0//EN">

2 Size Your Tag
Use a tag with a defined size. I was using a SPAN tag, and could not get it to work. When I added a size to the tag, it started working. You can set the size to zero px and let the browser stretch it out to fit the content, and that seems to work. You only need to use one dimension for it to work. Wierd!

3 Use The Full ProgID
You may need to use the full progId to define the filter. Many web sites don't and it seems to work fine, sometimes. When in doubt, use the full progID of the filter, like so...
<!-- Use the full progid if filters aren't showing up -->
<
span style="height:0; filter: progid:DXImageTransform.Microsoft.Glow(Color=blue, Strength=2), progid:DXImageTransform.Microsoft.Shadow(color:red, direction:135, strength=5);">Born on the 4th Of July</span>
Born on the 4th Of July

10.12.2006

Load text file into a string

This function loads a string from a text file and caches it using the System.Web caching object. I have to go track down this code snippet frequently. Thought I would post it here so I can find it later.

/// <summary>
///
    Load a text file from the file system
/// </summary>
///
<param name="filePath">File path of file to load</param>
///
<returns>Text file contents</returns>
protected string LoadFromFile(string filePath)
{
    
string fileContents = "";

    
// Load the content from a file and cache it
    if (HttpContext.Current.Cache[filePath] == null)
    {
        
// Load template from a file
        StreamReader reader = File.OpenText(filePath);
        fileContents = reader.ReadToEnd();
        reader.Close();

        
// Cache it
        System.Web.HttpContext.Current.Cache.Insert(filePath, fileContents, new CacheDependency(filePath));
    }
    
else
    {
        
// Read template from cache
        fileContents = (string) HttpContext.Current.Cache[filePath];
    }

    
return fileContents;
}        

SQL Reporting Services Parameter Dependency Trick

SQL Server Reporting Services has a bug that annoys me. I have a report with SQL based parameters (a dropdown list), and a date range that I default using a Reporting Service expression.

The bug occurs when users run the report multiple times. Changing the dropdown option reverts the date to the default. Reporting Services assumes that a change in the dropdown should revert all non-sql based parameters to their default values. Very annoying for the users, and there's no way around it in the current version of Reporting Services using parameter dependencies.

The workaround I came up with is simply to change the date parameter and make it a SQL query rather than a Reporting Services expression. This prevents or tricks Reporting Services into leaving the parameter alone when users change other SQL-based parameters. I added a DataSet containing a SQL query with my date logic (in this case, the first date of the current month).

//************************************************************
// Default report date to the first day of current month
// -----------------------------------------------------------
// Note: We use a dataset for this instead of an expression
// to avoid parameter dependencies, which cause our dates to
// get reset when the location parameter is changed in the
// Reporting Services report viewer
//************************************************************
SELECT REPORT_DATE = DATEADD(m, -1, DATEADD(m, DATEDIFF(m, 0, GETDATE()), 0))

Query Prior Friday From SQL Server

SQL Server TSQL query to return the last friday, based on the current date. This technique can also be modified to return any other day of the week or to get the next Friday, etc.

--Returns previous friday based on the current date
SELECTEND_DATE = DATEADD(d, (DATEDIFF (d, '20000108', GETDATE()) / 7) * 7, '20000107')

Convert ArrayList to object array

I need to create an ArrayList to and array of entity objects. In this sample, an array of Person objects. I need to build the array dynamically, and I'd like to use the intrinsic .Net System.Collection classes. In this sample, we'll use an ArrayList object.

Once we've created the ArrayList and added all the people to it, we want to convert it to an array of Person objects. The cast is a little wierd, and took me a while to figure out...

// Create an ArrayList and add some people to it
ArrayList peopleList = new ArrayList();
peopleList.Add(
new Person("Mickey", "Mouse"));
peopleList.Add(
new Person("Minny", "Mouse"));
peopleList.Add(
new Person("Donald", "Duck"));

// Finally, convert it to a typed array object
Person[] peopleArray = (Person[]) peopleList.ToArray(typeof(Person));