navigation
 Monday, September 25, 2006

I hate writing the same code over and over again. Whenever I do, ennui begins to set in and even writing the same five lines of code again suddenly becomes unbearable. That’s usually a good time to refactor the duplicate code into a method or utility class. I recently found myself writing some code like this that defied the usual Extract Method refactoring: code that created and opened a connection, created a command, executed a reader, iterated through the reader’s results, and did something on every record. Read on to see how to refactor this code into its own reusable class by applying the Template Method Design Pattern...

First let’s take a look at the shape of the code I was writing to examine why Extract Method wasn’t an appropriate refactoring. The code looked something like this:

using ( SqlConnection connection = new SqlConnection() )
{
  using ( SqlCommand command = new SqlCommand() )
  {
    using ( SqlDataReader reader = command.ExecuteReader() )
    {
      while ( reader.Read() )
      {
        // Do something
      }
    }
  }
}

All I really wanted to do was get at that SqlDataReader and process its results. However, I couldn’t just define a method that returned the SqlDataReader from the innermost using statement, because once the using statements are exited, the objects are disposed, so I would be left with a reference to a SqlDataReader with no open SqlConnection. However, there is a design pattern that will solve this problem: the Template Method pattern.

Strictly defined, the Template Method is a pattern whose intent is “Define the skeleton of an algorithm in an operation, deferring some steps to subclasses.” (Gamma, Erich, Richard Helm, Ralph Johnson, and John Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software.) Let’s take that basic idea of defining the skeleton of an algorithm and deferring some steps, and apply it to this problem.

First of all, when I execute code like this, it’s usually a one-time kind of thing, so I don’t really want to have to define a new subclass every time I want to use my new Template Method implementation. Instead, I’m going to define a class that offers events that can be handled to provide the same kind of functionality.

The heart of my new Template Method implementation is the method that defines the skeleton that I keep finding myself writing, and all other design decisions will flow from it. In order for the method to be flexible, I’ll need to be able to pass a ConnectionString, some CommandText, a CommandType, a flexible number of parameters, and maybe a CommandBehavior. That’s a mouthful, and yet I want to keep the actual method signature as small as possible. Since it’s more common to execute multiple commands against the same connection than it is to execute the same command against multiple connections, I decided to make ConnectionString a property of the class rather than a parameter of the method. I’ve observed that the CommandBehavior parameter of SqlCommand.ExecuteReader() is often either omitted or fairly constant; I almost always use CommandBehavior.SingleResult. At any rate, I think that this is another parameter that is better left as a property of the class rather than part of the method signature. That leaves me with CommandText, CommandType, and SqlParameters as my method parameters.

The whole point of this Template Method was to provide a simple way to inject specific logic into the skeleton of some standard data-access logic. I chose to do this with events so I wouldn’t have to define subclasses every time I wanted different logic. In my experience, the two most common places that I do stuff with a SqlDataReader is on each record (processing data), and after the DataReader is closed (reading output parameters). Since I want this new class to be flexible, I will also provide an event that is raised when the DataReader moves from one result to the next. I’ll define a catch-all event type that provides access to the SqlDataReader (for access to the data) and the SqlCommand (for access to the output parameters), and then define three events all of this type that get raised on Read, on NextResult, and on Close. Let’s take a look at the final result of all these decisions:

public int Execute( string commandText, CommandType commandType, params SqlParameter[] parameters )
{
  using ( SqlConnection connection = new SqlConnection( _ConnectionString ) )
  {
    using ( SqlCommand command = new SqlCommand( commandText, connection ) )
    {
      command.CommandType = commandType;
      AddParameters( command, parameters );
      connection.Open();
      using ( SqlDataReader reader = command.ExecuteReader( _Behavior ) )
      {
        ReaderCommandEventArgs args = new ReaderCommandEventArgs( command, reader );
        do
        {
          RaiseEvent( NextResult, args );
          while ( reader.Read() )
            RaiseEvent( Read, args );
        } while ( reader.NextResult() );
        reader.Close();
        RaiseEvent( Close, args );
        return reader.RecordsAffected;
      }
    }
  }
}

AddParameters() is a helper method that adds the parameters to the command, but doesn’t throw an exception if the array is null. RaiseEvent() is another helper method that raises assigned event handlers while skipping unassigned ones.

My new Template Method class is ready for use! I've decided to call it a ReaderCommand, since it invokes the ExecuteReader method of a SqlCommand. Let’s compare the old code with the equivalent code using my new class. Here’s the old code:

using ( SqlConnection connection = new SqlConnection( connectionString ) )
{
  using ( SqlCommand command = new SqlCommand( commandText, connection ) )
  {
    command.Parameters.AddWithValue( "@Param1", "abc" );
    command.Parameters.AddWithValue( "@Param2", 123 );
    connection.Open();
    using ( SqlDataReader reader = command.ExecuteReader( CommandBehavior.SingleResult ) )
    {
      while ( reader.Read() )
        Console.WriteLine( reader[ 0 ] );
    }
  }
}

It’s not that this code is so bad, but there is a lot of boilerplate code in there, with the important varying bits scattered throughout, and no less than four levels of indentation, with the most important logic at the center of it all. Here’s the new code:

ReaderCommand rc = new ReaderCommand( connectionString, CommandBehavior.SingleResult );
rc.Read += new ReaderCommandEventHandler( rc_Read );
rc.Execute( commandText, CommandType.Text, new SqlParameter( "@Param1", "abc" ), new SqlParameter( "@Param2", 123 ) );

static void rc_Read( object sender, ReaderCommandEventArgs e )
{
  Console.WriteLine( e.Reader[ 0 ] );
}

The old code was 14 lines long, with data access and program logic all jumbled together. The new code is 7 lines long (and 3 of those line were auto-generated by the IDE), with the program logic cleanly separated from the data access. The result is code that is easier to read and easier to write.

Today I’ve demonstrated how the Template Method design pattern can reduce redundant code and result in code that is easier to read and write. I hope that this example will inspire you to refactor your own redundant code into reusable classes. For more information on this topic, I highly recommend Head First Design Patterns by Freeman & Freeman as an excellent way to get started with design patterns, and Design Patterns by Erich Gamma, et al. as the definitive initial catalog.

 | 
posted on September 25, 2006  #    by Adam Anderson  Comments [0] Trackback

Falafel Software launched their fast and easy to use web site that promotes their software development, consulting, and training services. In addition to promoting Falafel’s products and services, the site also features informative blogs by Falafel employees, an active community forum, and a store where Falafel and AutomatedQA products can be purchased.

The site also marks the debut of Falafel’s new creative director, Eric Titolo. On the Falafel web site, Eric spent many hours researching the previous Falafel sites trying to figure the best way of presenting the products and services Falafel has to offer.

“One the of the first things a web designer should do before even attempting a look and feel is to really sit down and contemplate the existing content,” remarked Mr. Titolo. “You really need to determine whether the site is organized in a way that your customers will understand and is easy to use. If it isn’t, you’re ultimately wasting your time and money.”

After the Falafel team agreed on the site’s organization, they moved into the marketing and design. “It really started out as a joke,” chuckled Eric. “I made this design flat with a graphic of a delicious looking falafel sandwich. Then I started thinking: why not make reference to food in the company’s slogan? There’s plenty of sayings in food services that can cross over into software. So I came up with the slogan ‘Made to Order’.”

Regardless of starting as a joke, the “made to order” slogan captures the philosophy of Falafel Software. Falafel provides top quality software, consulting, and training that meets the individual needs of every one of their clients. In other words, Falafel Software specializes in making sure your project is made to order.

“I absolutely loved the new slogan,” exclaimed Ramesh Theivendran, Principal Architect. “It makes me hungry just thinking about it!”

“I am extremely happy with the new web site. I think it really reflects who we are and where we are going,” remarked president, Lino Tadros. “Falafel prides itself on providing top quality products and services that are truly ‘made to order.’ Our new web site allows us to promote our objectives confidently and tastefully.”

posted on September 25, 2006  #    by Lino Tadros  Comments [0] Trackback
 Friday, September 22, 2006

Written by Phillip Blanton

There seems to be a lot of trouble encountered by people attempting their first install of DotnetNuke 4.x. I have developed a step by step guide for installing a new Dnn4 development system on your Windows XP machine, and I find that I am constantly looking for the last place I posted it so that I can copy and paste it into a new thread.

I figured that Falafel would be a good place to stick it. That way I can just post a link to this one static location whenever I need to share this information.

If you follow these steps to the letter, you *WILL* have a DotNetNuke installation running on Windows XP Professional. If you want to then open and compile the solution in Visual Studio, that is the subject of another post, but let's first get you installed...

-----
Update: There is a lot of confusion about which system account needs permission to the database and directory structure of your DNN installation. It used to be "ASPNET" on non XP and Server 2000 machines, and "NETWORK SERVICE" on Windows Server 2003 machines. Now it is a little more complicated.

If you are running IIS 6, then you should use "NETWORK SERVICE". If you are using IIS 5.x, then  you should use "ASPNET". Without regard to the OS.

The rese of these instructions will refer to "ASP System Account". Please substitute either ASPNET or  "NETWORK SERVICE" as appropriate to your version of IIS.
-----

1. Unzip the DotNetNuke 4.x Source Install zip into an empty directory where it will reside on your machine. In my case that is D:\Development\WebProjects\DnnDev.

2. Right click on the DnnDev directory and select "Sharing and Security" and click the Security tab.

(If you don't have a security tab, click "Tools | Folder Options", select the "View" tab, scroll to the bottom and turn off simple file sharing. Close the dialog and repeat step 2.)

3. Click the "Add" button and in the "Enter the Object Names to Select" area, enter the necessary
ASP System Account.

4. Click the [Check Names] button and the system username will be verified and fully qualified. Click OK.

5. Select the new user account and give it "Modify" permission. It doesn't need "Full Control". Click OK.

6. Back in the WebRoot directory, Make a copy of the release.config file and rename it "web.config". Also copy the \config\SiteUrls.config file to WebRoot.

7. Open the web.config file in a text editor (Textpad is the best, so go buy it now!) I use SQLServer Developer edition and not SQL Server Express so these directions are for SQL Server.

Comment out the two SQL Express SiteSqlServer keys, and uncomment the SQL Server 2000 / 2005 ones and set the "value" element of them both as follows...

"Server=(local);Database=DnnDev;trusted_connection=yes;"

Make both SiteSqlServer keys have the same connection string. Save and close the text editor. Don't modify anything else in the web.config file.

-----
SQL Server:

 This is slightly different in SQL Server 2005 and SQLServer 2000, but the concepts are the same.

Before you create the database...

8. Start up SQL Server Enterprise Manager and expand the "Security" section. Make sure
the ASP System Account has been added to the list of "Logins" and given default access to "master".

9. Collapse the security node, right click on the "Databases" node and select "New Database". Name the database DnnDev (or whatever you called it in the connection strings in step 7). Accept all defaults and let the Enterprise Manager create the database.

10. Expand the new DnnDev database node and select "Users". Right click in the users area and select "New Database User". From the drop down list, select the
ASP System Account account you just created. Give it dbowner access. Click OK.

Close the SQL Server Enterprise Manager.

-----
IIS Administrator:

11. Open IIS Adminstrator applet and add a new virtual directory to the default website. Name it "DnnDev", point it to the
D:\Development\WebProjects\DnnDev directory. Make sure "Read" and "Run Scripts" are checked and accept all other defaults.

12. Right Click
the new website entry in IIS and click "Properties". Select the "ASP.NET" tab and make sure you are running the 2.0.50215.0 version of ASP.NET.

Setup is now complete. If there is not a problem with the system, opening up IE or Firefox and navigating to http://localhost/dnndev will instantiate the DotNetNuke installer. After the installer has completed, there will be a link at the bottom of the page that will take you to the new portal site. Installation will only run once. After which point, navigating to http://localhost/dnndev
will just display the site.

posted on September 22, 2006  #    by Lino Tadros  Comments [0] Trackback
 Saturday, September 16, 2006

If you have a BoundField in a GridView that displays a datetime, but you only want to display the date, how would you go about doing that?

Set the DataFormatString to "{0:d}" ?

That is what I thought too. Turns out, this doesn't always work.
That is because by default the value is extracted from the data store, HtmlEncoded, and then the format string is applied. After HtmlEncoding,  the format string won't do anything. The fix in most cases, is usually pretty simple. Just turn off HtmlEncoding for that field by setting HtmlEncode="false".
If you can't turn off HtmlEncoding, it looks like there is some custom formating in your future.

posted on September 16, 2006  #    by Mike Dugan  Comments [0] Trackback
 Tuesday, September 05, 2006

I recently ran into a problem with a large DataSet when I set the EnforceConstraints to true. It gave me the error “Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints.” without any clue as to where to look or what to do. Googling the problem, I came across a blog by Dave Lloyd with a good method to figure out exactly where the error is. The only problem was the example code was Dimmed. Naturally I un-Dimmed the code and put it in a proper C# format. I then encapsulated it into a nice little static function that returns a NameValueCollection loaded with all of the relevant error info. The info returned tells you what table, what row/column, and what the constraint is.

private static NameValueCollection BuildDataSetErrorInfo(DataSet dataSet)     
        {     
            NameValueCollection errorInfo = new NameValueCollection();     
            errorInfo.Add("DataSetName: ", dataSet.DataSetName);     
            foreach (DataTable table in dataSet.Tables)     
            {     
                DataRow[] rows = table.GetErrors();     
                if ((rows != null) && (rows.Length > 0))     
                {     
                    errorInfo.Add("Table: ", table.TableName);     
                    foreach (DataRow row in rows)     
                    {     
                        errorInfo.Add("Row Error: ", row.RowError);     
                        DataColumn[] cols = row.GetColumnsInError();     
                        if ((cols != null) && (cols.Length > 0))     
                        {     
                            foreach (DataColumn col in cols)     
                            {     
                                errorInfo.Add("Column: ", col.ColumnName);     
                                errorInfo.Add("Column Error: ", row.GetColumnError(col));     
                            }     
                        }     
                    }     
                }     
            }     
            return errorInfo;     
        }   
 
posted on September 5, 2006  #    by Bary Nusz  Comments [0] Trackback
 Wednesday, August 16, 2006

If you add an item using the indexer, like this:

Cache["TestItem"] = value;

The item is added to the cache with no expiration policy and a normal priority. As a result, the item will stick around indefinitely.
We can help the cache decide which items to toss out of memory by specifying an expiration policy and/or a priority:

Cache.Insert("TestItem", value, null, Cache.NoAbsoluteExpiration,
  TimeSpan.FromMinutes(20), CacheItemPriority.Normal, null)

Above, I gave the item a 20 minute sliding expiration. This means each time the item is accessed, its 20 minute lease on life is renewed.
I could have told it to expire after exactly 20 mins, no matter how many times it is accessed by setting an absolute expiration instead:

Cache.Insert("TestItem", value, null, DateTime.Now.AddMinutes(20),
  Cache.NoSlidingExpiration, CacheItemPriority.Normal, null)

And to really take control of the scavenging mechanism, you can change the priority of items added to the cache. Lower priority, means it is removed first when system resources are running low. The values range from "Low" to "NotRemovable". See the CacheItemPriority type's documentation for all of the values.

You will also notice that the Cache has an "Add" method. If you choose to use the Add method, adding a key that already exists in the cache will result in an exception, while doing the same with the Insert method will overwrite it. Setting a value using the indexer is equivalent to this call:

Cache.Insert("TestItem", value, null, Cache.NoAbsoluteExpiration,
  Cache.NoSlidingExpiration, CacheItemPriority.Normal, null)

posted on August 16, 2006  #    by Mike Dugan  Comments [0] Trackback
 Sunday, August 13, 2006

For those who know me, it will come as no surprise that the first mobile web site that I will cover is a weather site. Although there are many weather sites, few are worth mentioning. http://mobile.wunderground.com/ is absolutely the best weather site for your mobile device. If you’ve been inside all day and hear distant thunder, you can quickly pull up your local radar, check for severe weather warnings, and your forecast. All of these pages are stripped down to just the facts. For more serious weather nerds, radar animations, storm tracks, and a quick view of all severe weather in the nation are available. Mark this site now!

posted on August 13, 2006  #    by Bary Nusz  Comments [0] Trackback
 Monday, July 24, 2006

As an application developer, I often need to generate scripts for mutiple database objects, each in its own file, with both a DROP and a CREATE statement. In SQL Server 2000, there was a robust set of scripting options to choose from which allowed exactly this kind of use. However, in SQL Server 2005, these options have vanished. All selected objects get put into a single script file, and there is no way to generate DROP and CREATE in a single script. Some options can be accessed by choosing the Tasks | Generate Scripts... menu item at the database level, but they don't provide the desired functionality, and the wizard itself is cumbersome to navigate.

In response to this loss of functionality, Bill Graziano wrote a utility that mimics these commonly-used options of SQL scripting. The original blog, which contains links to an installer as well as source code, can be found here.

posted on July 24, 2006  #    by Adam Anderson  Comments [0] Trackback
 Monday, June 05, 2006

A lot has been written about the merits of multiple narrow indexes versus single larger compound indexes. This blog by Grant Fritchey yields juicy food for thought on that very topic, backed by some very thorough testing with real-world data.

posted on June 5, 2006  #    by Adam Anderson  Comments [0] Trackback