Archive for 2010

jQuery Validation – Show & Focus on first error only!

Have you ever wanted to show one error message at a time, or create a different type of visual queue for a specific invalid element on a form? Using the validate options, you can easily create any effect you want.

The example below, is designed to show the first error message in a form and to set focus on that first element. The message is displayed in a basic JavaScript alert box, not very elegant but it makes for a simple demo.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Show JS Alert - First Validation Error</title>
    <script src="Scripts/jquery-1.4.2.js" type="text/javascript"></script>
    <script src="Scripts/jquery.validate.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(document).ready(function() {
            $("#elForm").validate({
                onfocusout: false,
                invalidHandler: function(form, validator) {
                    var errors = validator.numberOfInvalids();
                    if (errors) {
                        alert(validator.errorList[0].message);
                        validator.errorList[0].element.focus();
                    }
                },
                rules: {
                    TextBox1: { required: true, minlength: 2 },
                    TextBox2: { required: true, minlength: 2 },
                    TextBox3: { required: true, minlength: 2 }
                },
                messages: {
                    TextBox1: { required: "TextBox1 Required", minlength: "TextBox1 MinLength" },
                    TextBox2: { required: "TextBox2 Required", minlength: "TextBox2 MinLength" },
                    TextBox3: { required: "TextBox3 Required", minlength: "TextBox3 MinLength" }
                },
                errorPlacement: function(error, element) {
                    // Override error placement to not show error messages beside elements //
                }
            });
        });
    </script>

    <style type="text/css">
        label { width: 90px; display: block; float: left; }
        ul { list-style: none; }
        ul li { line-height: 1.8; }
    </style>
</head>
<body>
    <form id="elForm" action="#">
    <div>
        <h1>jQuery Validation - Show First Error Only</h1>
        <ul>
            <li><label>Text Box 1</label><input type="text" name="TextBox1" id="TextBox1" value="" /></li>
            <li><label>Text Box 2</label><input type="text" name="TextBox2" id="TextBox2" value="" /></li>
            <li><label>Text Box 3</label><input type="text" name="TextBox3" id="TextBox3" value="" /></li>
        </ul>
        <input type="submit" id="submit" value="Validate" />
    </div>
    </form>
</body>
</html>

Here are the important parts to focus on.

1. invalidHandler, this option give you access to the current validator and all the errors messages/items via the “validator.errorlist”.

invalidHandler: function(form, validator) {
	var errors = validator.numberOfInvalids();
	if (errors) {
		alert(validator.errorList[0].message);  //Only show first invalid rule message!!!
		validator.errorList[0].element.focus(); //Set Focus
	}
}

2. errorPlacement, this function controls how error messages are displayed. Since we don’t want any error messages displayed by default, we can override the default errorPlacement with a empty method call.

errorPlacement: function(error, element) {
	// Override error placement to not show error messages beside elements //
}

The end result is a alert box showing the first broken rule for the first invalid element on the page. In the example each input has 2 rules (required and minLength), if you enter a single character into the first text box the message will change from “TextBox1 Required” to “TextBox1 MinLength”.

Download JSON to CSV using JavaScript

Here is a simple way to convert your JSON to CSV, if your using FF or Chrome that supports data URI’s then this function convert your data and tell your browser to download the results as a text file. If you are using Internet Explorer (“IE”), a new window will popup so you can copy & paste or to use File -> Save As to download the results as text. The JSON parsing is done with json.org’s open source JSON parser, which you can download here.

Why can’t IE download the file to CSV like FireFox? The long answer is due to IE’s data URI support that was missing until IE8, and when implemented in IE8+, the security restrictions are set to prevent solutions like this from working! To force a download of your JSON data in CSV via IE, you’ll need to use an alternative technique like Server Side Parsing.

function DownloadJSON2CSV(objArray)
{
	var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
	var str = '';

	for (var i = 0; i < array.length; i++) {
		var line = '';
		for (var index in array[i]) {
			if(line != '') line += ','

			line += array[i][index];
		}

		str += line + '\r\n';
	}

	if (navigator.appName != 'Microsoft Internet Explorer')
	{
		window.open('data:text/csv;charset=utf-8,' + escape(str));
	}
	else
	{
		var popup = window.open('','csv','');
		popup.document.body.innerHTML = '<pre>' + str + '</pre>';
	}
}

WordPress 3.0 – A CMS Solution?

I started working on a project site that is going to use WordPress as the CMS engine. I wasn’t sure if this was going to work, but after a little time I found this was pretty easy to do. You start by deleting all the default content and disabling the default plug-ins and management screen options. Once everything is removed/disabled, you start by creating pages (e.g. Home, About, News, etc…) that will display all the content you need on the website. One you have your main page setup (e.g. Home), you need to change the default home page from a dynamic page of blog posts to a static page. You change the default home page under Settings –> Reading –> Front Page Display –> A Static Page –> Choose an option from the Front Page drop down list. That’s it, you now have WordPress running as a basic CMS soltuion.

I wish I could say that’s it, but most likely you’ll need to download and install some additional plug-ins. I found many plug-ins still do not support WordPress 3.0, so you’ll need to be careful! If you happen to install a bad plug-in, there is an easy fix to get you site back online… Delete the plug-in folder (via FTP or Hosting Control Panel) and WordPress will automatically disable the plug-in.

Here is the list of plug-ins I added for my project:

  1. Contact Form 7
    This is a great plug-in, it provides a easy way to create forms that get emailed to you. You create the forms using HTML online and a shortcode style syntax for the input fields. The shortcode inputs are then accessible in your email, that you also create using HTML.
  2. WP Google Maps
    This is a very basic Google Maps plug-in, the is about 10 options and the only think extra you need is a GoogleMaps API key.
  3. WordPress.com Stats
    I’ve been using this on my blog and love the UI. I wish this was all being done client-side, but for some reason it was created as service. By default it injects a smiley face into your page, so make sure you disable this in your themes style sheet.

The only other thing I added was a SSL plug-in that I created based on 3 other plug-ins. I created my own, so I could force WP to load specific pages as HTTPS and then default back to HTTP if it was not explicitly set to support SSL. I found most of the default plug-ins will leave the user browsing in SSL after they visit a SSL page, I didn’t want this and my plug-ins solves this problem.

<?php
/*
Plugin Name: WPSSL Force SSL
Plugin URI:
Description: This plug-in is based on WPSSL, forcessl and various other posts/comments I found while searching for a soltuion.  The plug-in is used by adding the meta tag "force_ssl" with any value to any pages where you want SSL ("HTTPS") enabled.  If the page does NOT have this set and your not looking at an admin page (you can enable SSL for admin/login page in wpconfig.php), then display as HTTP.  This prevent links on the SSL page from displaying as SSL for non-secure pages.  This plug-in was tested on WordPress 3.0.
Author: Zachary Hunter (based on Austin Web Development)
Version: 1.0
Author URI: 

*/

function wpssl_forcessl()
{
	global $post;

    $post_id = $post;

    if (is_object($post_id))
    {
		$post_id = $post_id->ID;
	}

    $force_ssl  = get_post_meta($post_id, 'force_ssl');

    if(!empty($force_ssl))
    {
    	if(!stristr($_SERVER['REQUEST_URI'], 'wp-admin')) {
			if($_SERVER["HTTPS"] != "on") {
				$newurl = "https://" . $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];
            	header("Location: $newurl");
            	exit();
        	}
     	}
    } else {
		if(!stristr($_SERVER['REQUEST_URI'], 'wp-admin')) {
			if($_SERVER["HTTPS"] == "on") {
				$newurl = "http://" . $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];
				header("Location: $newurl");
				exit();
			}
	}	}
}

add_action('wp', 'wpssl_forcessl');
?>

To use the plug-in follow these steps.

1. Copy the code above into a file in your plugin folder (e.g. /wp-content/plugins/wpssl/wpssl.php).
2. Go to the Plugins -> Plugins and enable “WPSSL Force SSL”.
2. Go to the Page you want to force SSL and open the “Custom Fields” section.
3. Click “Add Custom Field”, and use the settings below (name = force_ssl, value = true).
** DONE **

Improved NPOI ExportToExcel Function

I was looking over my generic export DataTable to Excel function the other day and noticed an issue. My default method was throwing everything into a string format, which was preventing users from highlighting number columns for subtotals. To fix the problem they could use “Text to Columns”, but this was becoming a common complaint I wanted to resolve. I came up with an improved “ExportToExcel” function that will insert the correct data type.

/// <summary>
///   Render DataTable to Excel File
/// </summary>
/// <param name = "sourceTable">Source DataTable</param>
/// <param name = "fileName">Destination File Name</param>
public static void ExportToExcel(DataTable sourceTable, string fileName)
{
	HSSFWorkbook workbook = new HSSFWorkbook();
	Sheet sheet = workbook.CreateSheet("Sheet1");
	Row headerRow = sheet.CreateRow(0);

	// Create Header Style
	CellStyle headerCellStyle = workbook.CreateCellStyle();
	headerCellStyle.FillForegroundColor = HSSFColor.GREY_25_PERCENT.index;
	headerCellStyle.FillPattern = FillPatternType.SOLID_FOREGROUND;

	// Create Date Style
	CellStyle dateCellStyle = workbook.CreateCellStyle();
	dateCellStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("m/d/yy");

	// Build Header
	foreach (DataColumn column in sourceTable.Columns)
	{
		Cell headerCell = headerRow.CreateCell(column.Ordinal);
		headerCell.SetCellValue(column.ColumnName);
		headerCell.CellStyle = headerCellStyle;
	}

	// Build Details (rows)
	int rowIndex = 1;
	int sheetIndex = 1;
	const int maxRows = 65536;

	foreach (DataRow row in sourceTable.Rows)
	{
		// Start new sheet max rows reached
		if (rowIndex % maxRows == 0)
		{
			// Auto size columns on current sheet
			for (int h = 0; h < headerRow.LastCellNum; h++)
			{
				sheet.AutoSizeColumn(h);
			}

			sheetIndex++;
			sheet = workbook.CreateSheet("Sheet" + sheetIndex);
			Row additionalHeaderRow = sheet.CreateRow(0);

			for (int h = 0; h < headerRow.LastCellNum; h++)
			{
				Cell additionalHeaderColumn = additionalHeaderRow.CreateCell(h);
				additionalHeaderColumn.CellStyle = headerRow.GetCell(h).CellStyle;
				additionalHeaderColumn.SetCellValue(headerRow.GetCell(h).RichStringCellValue);
			}

			rowIndex = 1;
		}

		// Create new row in sheet
		Row dataRow = sheet.CreateRow(rowIndex);

		foreach (DataColumn column in sourceTable.Columns)
		{
			Cell dataCell = dataRow.CreateCell(column.Ordinal);

			switch (column.DataType.FullName)
			{
				case "System.String":
					dataCell.SetCellValue(row[column].ToString());
					break;
				case "System.Int":
				case "System.Int32":
				case "System.Int64":
				case "System.Double":
				case "System.Decimal":
					double val;
					dataCell.SetCellValue(Double.TryParse(row[column].ToString(), out val) ? val : 0);
					break;
				case "System.DateTime":
					DateTime dt = new DateTime(1900, 01, 01);
					DateTime.TryParse(row[column].ToString(), out dt);

					dataCell.SetCellValue(dt);
					dataCell.CellStyle = dateCellStyle;
					break;
				default:
					dataCell.SetCellValue(row[column].ToString());
					break;
			}
		}

		rowIndex++;
	}

	for (int h = 0; h < headerRow.LastCellNum; h++)
	{
		sheet.AutoSizeColumn(h);
	}

	ExportToExcel(workbook, fileName);
}

The key part of the function above to review is the “switch (column.DataType.FullName)” code block. This grabs the DataTable’s column data type to use in the SetCellValue() call.

Once the workbook is built, we call a overload of the same function that expects a NPOI workbook. This overload will send a XLS file back to the user via their web browser using the HttpResponse stream.

/// <summary>
/// Render Excel File to HttpResponse (Browser)
/// </summary>
/// <param name="workbook">NPOI Workbook</param>
/// <param name="fileName">Destination File Name</param>
public static void ExportToExcel(HSSFWorkbook workbook, string fileName)
{
	using (MemoryStream memoryStream = new MemoryStream())
	{
		workbook.Write(memoryStream);
		memoryStream.Flush();

		try
		{
			HttpResponse response = HttpContext.Current.Response;
			response.ClearContent();
			response.ClearHeaders();
			response.Buffer = true;
			response.ContentType = "application/vnd.ms-excel";
			response.AddHeader("Content-Length", memoryStream.Length.ToString());
			response.AddHeader("Content-Disposition", string.Format("attachment;filename={0}", fileName));
			response.BinaryWrite(memoryStream.GetBuffer());
			response.Flush();
			response.End();
		}
		catch
		{
			// Do nothing, error expected due to Flush();
		}
	}
}

I’ve used the above function to send files with 3-4 sheets full of data back to the browser… but the file size is usually “VERY LARGE”. To work around this, I have a helper function which will add the excel file to a zip (in memory) before sending back to the client.

In my last test, a 17.5MB document with 2 sheets of data was compressed to 3.5MB with my zip utility. There was still a ~13 second delay to generate the XLS file, but once prompted to download form the browser the file download completed in a few seconds.

jQuery Validation with ASP.NET

Over the past few weeks I’ve been working to migrate away from the Ajax Control Toolkit & various other ASP.NET built-in controls. My goal has been to get every page of our intranet portal down around 100K, with a maximum load time of < 1 second. I’ve made a lot of progress, but after cleaning up all the basic stuff (excess view state, duplicate references, compressed JS/CSS, sprites, etc…), I had to start looking for additional items…

Using Fiddler and FireBug, I started looking for resources that were increasing my download sizes and found that the ASP.NET validation controls were generating ~10K each time they were used in a module. Since my portal consists of injecting multiple user controls into a page, this number would vary page-by-page based on the number of modules that used the library on one page. Since I was using jQuery for all my scripting, I decided to implement jQuery Validation Plugin as a replacement for the built-in ASP.NET validation controls.

The idea was simple enough, but since I’m living in ASP.NET Web Form world (aka: One form per/page) this was a bit more difficult to implement.

Issue #1 – jQuery Validation by FIELDSET

As noted, the default setup of the validation plug in is to validate a FORM which isn’t possible with ASP.NET Web Forms. To get around this, I decided I was going to wrap all my forms in a FIELDSET with the class “validationGroup”. Using this class as my selection, I’m able to have multiple groups of controls wrapped in a FIELDSET validated separately.

To get started, you need to create a custom validation function that will recursively move up the elements/groups to find a FIELDSET with the class “validationGroup”, and then check all the input elements against the rules assigned.

Here is my custom validation function:

function ValidateAndSubmit(evt) {
    var isValid = true;

    // Get Validator & Settings
    var validator = $("#aspnetForm").validate();
    var settings = validator.settings;

    // Find the parent control that contains the elements to be validated
    var $group = $(evt.currentTarget).parents('.validationGroup');

    // Grab all the input elements (minus items listed below)
    $group
        .find(":input")
        .not(":submit, :reset, :image, [disabled]")
        .not(settings.ignore)
        .each(function (i, item) {
            // Don't validate items without rules
            if (!validator.objectLength($(item).rules()))
                return true;

            if (!$(item).valid())
                isValid = false;
        });

    // If any control is the group fails, prevent default actions (aka: Submit)
    if (!isValid)
        evt.preventDefault();
}

Next, I need to trigger the validation for the current FIELDSET I’m working in based on on some action… like the click of a submit button. Since the default setting is to validation on submit, you need to disable this and register your ValidateAndSubmit function call when your event is triggered.

// Disable default/auto binding of all buttons
$("#aspnetForm").validate({
	onsubmit: false,
	ignore: ':hidden',
	focusInvalid: true
});

// Bind the ASP.NET button with the ID "Search" to the "ValidateAndSubmit" custom validation function.
$('#<%= Search.ClientID %>').click(ValidateAndSubmit);

That’s it, with those three little little steps (Custom Validate Method, Disable Default/Auto Bind, Manual bind button to custom event), you now have a working validate by FIELDSET (or any other grouping control) solution.

Issue #2 – How to validate a group of ASP.NET Check Boxes

By default, ASP.NET will render a CheckBox or a CheckBoxList with an auto generated unique name attribute. This becomes a problem when you want to validate the group, since you can’t set a common name attribute for all the elements.

Here is an example of the HTML that would be rendered by a CheckBoxList with a layout of “Flow”.

<span id="CheckBoxGroup">
  <input id="cbk1" name="cbk1" type="checkbox">Check Box 1</input>
  <input id="cbk2" name="cbk2" type="checkbox">Check Box 2</input>
  <input id="cbk3" name="cbk3" type="checkbox">Check Box 3</input>
</span>
<span class="jQueryValError"></span>

My solution to the problem required a custom validator and a custom errorPlacement function, for the jQuery validaiton plug-in.

First, I added a custom validator that looked at a group of check boxes that are inside a wrapping “Parent()” element. I then count the number of checked check boxes to make sure the limit required (e.g. Must check at least 3 check boxes) is greater than the minimum we set.

jQuery.validator.addMethod("minChecked",
 function(value, element, param) {
	var $p = $(element).parent();
	var selected = $p.children('input[type=checkbox]:checked').length;

	if (selected >= param) {
		$p.children().removeClass('error');
		$p.siblings('.error').remove();
		return true;
		}

	$p.children('input[type=checkbox]').addClass('error');

In order to hookup this custom event to all the controls inside of a wrapping “Parent()” control, we use jQuery’s $().each function to call the validator’s rules() function.

$(".checkBoxGroup").children('input[type=checkbox]').each(function(){ $(this).rules("add", { minChecked: 3}); });

Second, our plug-in will by default put an error message next to the control(s) that triggered the error. I over ride the default behavior, we setup a “errorPlacement” function to put one error beside the wrapping “Parent()” control.

$("#<%= form1.ClientID %>").validate({
	errorPlacement: function(error, element){
		if(element.rules().minChecked > 0) {
			var $p = $(element).parent();
			if($p.siblings().hasClass("error") == false) {
				error.insertAfter($p);
			}
		}
		else {
			error.insertAfter(element);
		}
	}
});

Here is what the form looks like when you have a error with your check boxes.

jQuery Validation of ASP.NET CheckBoxes

Here is source code used to create the example above.

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Contact Form Demo</title>

    <script src="styles/jQuery.js" type="text/javascript"></script>

    <script src="styles/jQuery.Validate.js" type="text/javascript"></script>

    <script src="styles/jQuery.Validate.AddOns.js" type="text/javascript"></script>

    <script type="text/javascript">

    jQuery.validator.addMethod("minChecked",
     function(value, element, param) {
        var $p = $(element).parent();
        var selected = $p.children('input[type=checkbox]:checked').length;

        if (selected >= param) {
            $p.children().removeClass('error');
            $p.siblings('.error').remove();
            return true;
            }

        $p.children('input[type=checkbox]').addClass('error');

        return false;}, jQuery.validator.format("Please check at least {0} items.")); 

        $(document).ready(function(){
            $("#<%= form1.ClientID %>").validate({
                rules: {
                    <%= FirstName.UniqueID %>: { required: true },
                    <%= LastName.UniqueID %>: { required: true },
                    <%= Email.UniqueID %>: { required: true, email: true },
                    <%= Phone.UniqueID %>: { required: true, phoneUS: true }
                },
                errorPlacement: function(error, element){
                    if(element.rules().minChecked > 0) {
                        var $p = $(element).parent();
                        if($p.siblings().hasClass("error") == false) {
                            error.insertAfter($p);
                        }
                    }
                    else {
                        error.insertAfter(element);
                    }
                }
            });

            $(".checkBoxGroup").children('input[type=checkbox]').each(function(){ $(this).rules("add", { minChecked: 3}); });

            $(".myGroupRandom").children('input[type=checkbox]').each(function(){ $(this).rules("add", { minChecked: 1}); });
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <fieldset>
            <ol>
                <li>
                    <label class="left">
                        First Name
                    </label>
                    <input type="text" id="FirstName" runat="server" /></li>
                <li>
                    <label class="left">
                        Last Name
                    </label>
                    <input type="text" id="LastName" runat="server" /></li>
                <li>
                    <label class="left">
                        Email
                    </label>
                    <input type="text" id="Email" runat="server" /></li>
                <li>
                    <label class="left">
                        Phone
                    </label>
                    <input type="text" id="Phone" runat="server" /></li>
                <li>
                    <label class="left">
                        Contact Method
                    </label>
                    <span class="checkBoxGroup">
                        <input type="checkbox" id="ReqEmail" runat="server" /><label>Email</label>
                        <input type="checkbox" id="ReqMail" runat="server" /><label>Mail</label>
                        <input type="checkbox" id="ReqPhone" runat="server" /><label>Phone</label>
                        <input type="checkbox" id="ReqNoContact" runat="server" /><label>No Contact</label>
                    </span></li>
                <li>
                    <label class="left">
                        New Letter Type
                    </label>
                    <span class="myGroupRandom" >
                        <input type="checkbox" id="Checkbox1" runat="server" /><label>Company News</label>
                        <input type="checkbox" id="Checkbox2" runat="server" /><label>Press Releases</label>
                        <input type="checkbox" id="Checkbox3" runat="server" /><label>Deals</label>
                        <input type="checkbox" id="Checkbox4" runat="server" /><label>Employement</label>
                    </span></li>
                <li>
                    <input type="submit" id="Submit" value="Submit" /></li>
            </ol>
        </fieldset>
    </div>
    </form>
</body>
</html>

NPOI – Set Cell Helper

I saw a discussion posting on the NPOI discussion forum on CodePlex today, asking if there was a function like SetCell(X,Y,Value) in NPOI. Unfortunately there isn’t… At least I was never able to find one, so I created my own. Since I only needed to set values I added three basic ones into my helper class to make available to everybody using NPOI in my project. I was really tempted to add these to the HSSFWorksheet, but to keep my code save I figured a helper class for all my extras would be enough. Here is my version of a SetCellValue() helper set of functions.

private static void SetCellValue(HSSFSheet worksheet, int columnPosition, int rowPosition, DateTime value)
{
	// Get row
	using (HSSFRow row = worksheet.GetRow(rowPosition))
	{
		// Get or Create Cell
		using (HSSFCell cell = row.GetCell(columnPosition) ?? row.CreateCell(columnPosition))
		{
			cell.SetCellValue(value);
			cell.CellStyle.DataFormat = 14;
		}
	}
}

private static void SetCellValue(HSSFSheet worksheet, int columnPosition, int rowPosition, double value)
{
	// Get row
	using (HSSFRow row = worksheet.GetRow(rowPosition))
	{
		// Get or Create Cell
		using (HSSFCell cell = row.GetCell(columnPosition) ?? row.CreateCell(columnPosition))
		{
			cell.SetCellValue(value);
		}
	}
}

private static void SetCellValue(HSSFSheet worksheet, int columnPosition, int rowPosition, string value)
{
	// Get row
	using (HSSFRow row = worksheet.GetRow(rowPosition))
	{
		// Get or Create Cell
		using (HSSFCell cell = row.GetCell(columnPosition) ?? row.CreateCell(columnPosition))
		{
			cell.SetCellValue(value);
		}
	}
}

// Set Date
SetCellValue(sheet, 9, 3, DateTime.Now);
// Set Number
SetCellValue(sheet, 9, 4, 100.01);
// Set Text
SetCellValue(sheet, 9, 5, "Zach Roxs!");

As you can see it’s pretty easy to create a SetCellValue() helper. I plan to create another version of these that uses Excel coordinates (e.g. A5, Z10, etc…), so my die hard Excel teammates can use their native Excel mapping syntax!

NPOI – Copy Row Helper

Another day and another little tidbit on using NPOI. I was doing tool mock-up at work today when I ran across a need for a copy row function. After searching high and low, I realized NPOI does not currently offer this capability. After looking around (Google, NPOI and POI threads) I decided to create my own helper function. I’m sure there might be a few things I missed in my routine since the library is a bit new to me, but after testing this against a bunch of different scenarios I’m pretty confident this will work for 99% of my needs and maybe a high percent of yours as well.

Here is the function in all it’s glory, I thought about modify the NPOI source but since I’m not sure where it’s going I figured I’d just add this in my own little NPOI.CustomHelpers class that I can use with my NPOI project.

/// <summary>
/// HSSFRow Copy Command
///
/// Description:  Inserts a existing row into a new row, will automatically push down
///               any existing rows.  Copy is done cell by cell and supports, and the
///               command tries to copy all properties available (style, merged cells, values, etc...)
/// </summary>
/// <param name="workbook">Workbook containing the worksheet that will be changed</param>
/// <param name="worksheet">WorkSheet containing rows to be copied</param>
/// <param name="sourceRowNum">Source Row Number</param>
/// <param name="destinationRowNum">Destination Row Number</param>
private void CopyRow(HSSFWorkbook workbook, HSSFSheet worksheet, int sourceRowNum, int destinationRowNum)
{
	// Get the source / new row
	HSSFRow newRow = worksheet.GetRow(destinationRowNum);
	HSSFRow sourceRow = worksheet.GetRow(sourceRowNum);

	// If the row exist in destination, push down all rows by 1 else create a new row
	if (newRow != null)
	{
		worksheet.ShiftRows(destinationRowNum, worksheet.LastRowNum, 1);
	}
	else
	{
		newRow = worksheet.CreateRow(destinationRowNum);
	}

	// Loop through source columns to add to new row
	for (int i = 0; i < sourceRow.LastCellNum; i++)
	{
		// Grab a copy of the old/new cell
		HSSFCell oldCell = sourceRow.GetCell(i);
		HSSFCell newCell = newRow.CreateCell(i);

		// If the old cell is null jump to next cell
		if (oldCell == null)
		{
			newCell = null;
			continue;
		}

		// Copy style from old cell and apply to new cell
		HSSFCellStyle newCellStyle = workbook.CreateCellStyle();
		newCellStyle.CloneStyleFrom(oldCell.CellStyle); ;
		newCell.CellStyle = newCellStyle;

		// If there is a cell comment, copy
		if (newCell.CellComment != null) newCell.CellComment = oldCell.CellComment;

		// If there is a cell hyperlink, copy
		if (oldCell.Hyperlink != null) newCell.Hyperlink = oldCell.Hyperlink;

		// Set the cell data type
		newCell.SetCellType(oldCell.CellType);

		// Set the cell data value
		switch (oldCell.CellType)
		{
			case HSSFCellType.BLANK:
				newCell.SetCellValue(oldCell.StringCellValue);
				break;
			case HSSFCellType.BOOLEAN:
				newCell.SetCellValue(oldCell.BooleanCellValue);
				break;
			case HSSFCellType.ERROR:
				newCell.SetCellErrorValue(oldCell.ErrorCellValue);
				break;
			case HSSFCellType.FORMULA:
				newCell.SetCellFormula(oldCell.CellFormula);
				break;
			case HSSFCellType.NUMERIC:
				newCell.SetCellValue(oldCell.NumericCellValue);
				break;
			case HSSFCellType.STRING:
				newCell.SetCellValue(oldCell.RichStringCellValue);
				break;
			case HSSFCellType.Unknown:
				newCell.SetCellValue(oldCell.StringCellValue);
				break;
		}
	}

	// If there are are any merged regions in the source row, copy to new row
	for (int i = 0; i < worksheet.NumMergedRegions; i++)
	{
		CellRangeAddress cellRangeAddress = worksheet.GetMergedRegion(i);
		if (cellRangeAddress.FirstRow == sourceRow.RowNum)
		{
			CellRangeAddress newCellRangeAddress = new CellRangeAddress(newRow.RowNum,
																		(newRow.RowNum +
																		 (cellRangeAddress.FirstRow -
																		  cellRangeAddress.LastRow)),
																		cellRangeAddress.FirstColumn,
																		cellRangeAddress.LastColumn);
			worksheet.AddMergedRegion(newCellRangeAddress);
		}
	}

}

The code comments above should give you a good idea of what I’m doing, if something doesn’t make sense just ask. The key things I wanted to make sure got copied were; Cell Style, Cell Value, Cell Type, Merged Cell Settings. In the end I noticed a few other things that I thought I might use in the future, so I included them as well. Here is an example of how to call to CopyRow along with a snapshot of the end result.

// Grab my NPOI workbook memorystream
HSSFWorkbook workbook = new HSSFWorkbook(memoryStream);

// Grab my test worksheet
HSSFSheet sheet = workbook.GetSheet("Sheet1");

// Copy Excel Row 1 to Excel Row 3
CopyRow(workbook, sheet, 0, 2);

// Copy Excel Row 2 to Excel Row 4
CopyRow(workbook, sheet, 1, 3);
NPOI – Copy Row Helper Function Test Results

Using jQuery to prevent “Delete” mistakes

A few days ago I was reading a web design article that talked about the “Poka-Yoke” principle. It was such a funny phrase that I had to go to Wikipedia to figure out the definition. In a nutshell, the principle refers to the process of “idiot-proofing” human interaction with a process. This term is based on the Japanese words “yokeru” avoid and “poka” mistake, this is rather funny for me since I work for a Japanese company that has clearly never heard of this principle!

This term came to mind today while helping another programmer develop a system to prevent accidental in their UI. After discussing what needed to be done, it was clear that we needed to implement some client side logic to “prevent… guide…” the user into making the correct choices.

The UI was pretty straight forward, there will be a few buttons to do various actions on rows in a table. The users will select one or more rows for the table and then click the button of the action they want to perform. Sounds simple, right… We’ll it is and it’s also really easy to select the wrong row and/or the wrong button. Training is a big help in any process, but one you leave the users alone the system will be the only thing enforcing the rules.

Here is an example of a table where rows will be selected for deletion. I used a “asp:Table” to simulate the markup for a table that will be generated with a “asp:GridView”. In my past 5 years of working with ASP.NET, this was the first time I ever used or seen this control used.

<div class="mediumTable">
	<asp:Button ID="DeleteButton" runat="server" Text="Delete" />
	<asp:Table ID="Table1" runat="server">
		<asp:TableHeaderRow>
			<asp:TableHeaderCell>Chk</asp:TableHeaderCell>
			<asp:TableHeaderCell>Product</asp:TableHeaderCell>
			<asp:TableHeaderCell>Stock</asp:TableHeaderCell>
		</asp:TableHeaderRow>
		<asp:TableRow>
			<asp:TableCell>
				<asp:CheckBox ID="CheckBox1" runat="server" /></asp:TableCell>
			<asp:TableCell>Apples</asp:TableCell>
			<asp:TableCell>0</asp:TableCell>
		</asp:TableRow>
		<asp:TableRow>
			<asp:TableCell>
				<asp:CheckBox ID="CheckBox2" runat="server" /></asp:TableCell>
			<asp:TableCell>Oranges</asp:TableCell>
			<asp:TableCell>100</asp:TableCell>
		</asp:TableRow>
		<asp:TableRow>
			<asp:TableCell>
				<asp:CheckBox ID="CheckBox3" runat="server" /></asp:TableCell>
			<asp:TableCell>Pears</asp:TableCell>
			<asp:TableCell>150</asp:TableCell>
		</asp:TableRow>
		<asp:TableRow>
			<asp:TableCell>
				<asp:CheckBox ID="CheckBox4" runat="server" /></asp:TableCell>
			<asp:TableCell>Watermelon</asp:TableCell>
			<asp:TableCell>2</asp:TableCell>
		</asp:TableRow>
	</asp:Table>
</div>
</form>

Here is the delete “prevention” system we came up. We had a few other ideas like, but after doing a few demos of each solution we decided on the following code that will be discussed below.

$(document).ready(function() {
	$('#<%= DeleteButton.ClientID %>').click(function() {
		// Find all selected items
		var CheckedCheckBoxes = $('#<%= Table1.ClientID %>').find("input[type='checkbox']:checked");
		// If there are no selected items, exit
		if (CheckedCheckBoxes.length == 0) {
			alert("You must make a selection before you can delete an item.");
			return false;
		}
		// If there are selected items, loop
		CheckedCheckBoxes.each(function() {
			var isProcessed = $(this).parent().parent().find('td:last').text();
			// If current item is already processed, set flat to true
			if (jQuery.trim(isProcessed) > 0) {
				deletedProcessed = true;
			}
		});
		// Check flag, if true stop ALL deletes and notify user
		if (deletedProcessed) {
			alert("You can't delete a product with stock!");
			return false;
		}
		else {
			// Do a final confirmation the user wants to delete the selection
			var answer = confirm('Are you sure you want to delete your selection?');
			return answer
		}
	});
});

Since selection box was used for a few different functions (process orders, hold orders and edit orders) we needed a way to add a little extra checking to only the delete button. Our goals with the logic above was the following.

  1. Disables “Delete” if nothing has been selected.
  2. Disables “Delete” if the user selected a item should not be deleted (e.g. Has Inventory).
  3. Prompts the user to confirm the really want to delete the item.

In addition to these ideas, we also had the following ideas…

  1. Alert row # of items that don’t meet the business rule
  2. Highlight the row in “red” that don’t meet the business rule
  3. Physically “Disable” the delete button if they select an item that don’t meet the business rules

Mistakes are human nature and by double and triple checking what they are doing we can save the users and ourselves from many emails/phone calls/visits about how the system “deleted the data all by itself”.

Mistake proofing is such an easy idea to grasp and agree with, that it’s surprising that we don’t see more of it in the systems we using everyday. I’m sure I’ve developed a few bad ones, hopefully the audience using it was small and it didn’t mitigate itself into other things. Working for a Japanese company who has developed some of the worst internal tools I’ve ever seen (0 UI design effort), I’m sure to bring up the new Japanese “Poka-Yoke” principle that next time I talk to one of the developers in Japan.

How to read in XLSX data for editing with NPOI

NPOI is a great solution for working with XLS documents, but what happens when you need to read in XLSX documents as part of your solution? The easiest solution I could think of was to use OLEDB to extract out all the data (the data, the whole data and nothing but the data) from a worksheet into a new NPOI document.

If you need more support than just reading in data from Excel 2007+ (XLSX), you should look at using the ExcelPackage project that is hosted at CodePlex.

The benefit to my approach, is that your able to use your existing NPOI solutions when data is provided in XLSX format. This is far from full Excel 2007+ support, but if your applicaitons only requirement is “reading in data” then your problem is solved. NPOI v1.6 is supposed to fully support the XLSX format, until then this function will provide basic XLSX support.

Functions used to convert XLSX document to a NPOI document
/// <summary>
/// Render a Excel 2007 (xlsx) Worksheet to NPOI Excel 2003 Worksheet, all excel formatting
/// from XLSX will be lost when converted.  NPOI roadmap shows v1.6 will support Excel 2007 (xlsx).
/// NPOI Roadmap  : http://npoi.codeplex.com/wikipage?title=NPOI%20Road%20Map&referringTitle=Documentation
/// NPOI Homepage : http://npoi.codeplex.com/
/// </summary>
/// <param name="excelFileStream">XLSX FileStream</param>
/// <param name="sheetName">Excel worksheet to convert</param>
/// <returns>MemoryStream containing NPOI Excel workbook</returns>
public static Stream ConvertXLSXWorksheetToXLSWorksheet(Stream excelFileStream, string sheetName)
{
	// Temp file name
	string tempFile = HttpContext.Current.Server.MapPath("~/uploads/" + HttpContext.Current.Session.LCID + ".tmp");

	// Temp data container (using DataTable to leverage existing RenderDataTableToExcel function)
	DataTable dt = new DataTable();

	try
	{
		// Create temp XLSX file
		FileStream fileStream = new FileStream(tempFile, FileMode.Create, FileAccess.Write);

		const int length = 256;
		Byte[] buffer = new Byte[length];
		int bytesRead = excelFileStream.Read(buffer, 0, length);

		while (bytesRead > 0)
		{
			fileStream.Write(buffer, 0, bytesRead);
			bytesRead = excelFileStream.Read(buffer, 0, length);
		}

		excelFileStream.Close();
		fileStream.Close();

		// Read temp XLSX file using OLEDB
		// Tested on Vista & Windows 2008 R2
		using (OleDbConnection con = new OleDbConnection(@"Provider=Microsoft.ACE.OLEDB.12.0; Extended Properties=Excel 12.0;Data Source=" + tempFile + @";Extended Properties=Excel 12.0;"))
		{
			con.Open();
			string sql = String.Format("SELECT * FROM [{0}$]", sheetName);
			OleDbDataAdapter da = new OleDbDataAdapter(sql, con);

			da.Fill(dt);
		}
	}
	finally
	{
		// Make sure temp file is deleted
		File.Delete(tempFile);
	}

	// Return a new POI Excel 2003 Workbook
	return RenderDataTableToExcel(dt);
}

/// <summary>
/// Render DataTable to NPOI Excel 2003 MemoryStream
/// NOTE:  Limitation of 65,536 rows suppored by XLS
/// </summary>
/// <param name="sourceTable">Source DataTable</param>
/// <returns>MemoryStream containing NPOI Excel workbook</returns>
public static Stream RenderDataTableToExcel(DataTable sourceTable)
{
	HSSFWorkbook workbook = new HSSFWorkbook();
	MemoryStream memoryStream = new MemoryStream();
	// By default NPOI creates "Sheet0" which is inconsistent with Excel using "Sheet1"
	HSSFSheet sheet = workbook.CreateSheet("Sheet1");
	HSSFRow headerRow = sheet.CreateRow(0);

	// Header Row
	foreach (DataColumn column in sourceTable.Columns)
		headerRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName);

	// Detail Rows
	int rowIndex = 1;

	foreach (DataRow row in sourceTable.Rows)
	{
		HSSFRow dataRow = sheet.CreateRow(rowIndex);

		foreach (DataColumn column in sourceTable.Columns)
		{
			dataRow.CreateCell(column.Ordinal).SetCellValue(row[column].ToString());
		}

		rowIndex++;
	}

	workbook.Write(memoryStream);
	memoryStream.Flush();
	memoryStream.Position = 0;

	return memoryStream;
}

NOTE: You could convert an entire workbook (multiple work sheets) into a new NPOI workbook if you looped over each work sheet in the XLSX document. Since all my tools are based on using a single work sheet, I’ll leave the workbook conversion up to you.

Example using XLSX function
if (FileUpload.PostedFile.ContentLength > 0)
{
	Stream uploadFileStream = FileUpload.PostedFile.InputStream;

	// If the file uploaded is "XLSX", convert it's Sheet1 to a NPOI document
	if (FileUpload.PostedFile.FileName.EndsWith("xlsx"))
	{
		uploadFileStream = ExcelHelper.ConvertXLSXWorksheetToXLSWorksheet(uploadFileStream, "Sheet1");
	}
}

** All your NPOI logic that adds columns, changes cell/row formatting, etc… will now work with the data extracted from the XLSX document.

Use NPOI to populate an Excel template

So I’ve been using NPOI all week and decide to do a quick “demo” for my team today. My demo was to show how to use NPOI to populate (update) an Excel template that includes various charts.  Even though NPOI does not support creating charts from scratch, it does support updating files that already include (hence template) charts. I started by going to the Microsoft website where they have a bunch of free “pretty” templates on, randomly choosing one with a bunch of formulas and charts.  It took me about an hour to build the complete demo using very simple and easy to read code. Most of the updates or just putting values in cells, but the actual process of opening/reading/inserting/saving a new or existing file in NPOI is very easy for a novice programmers.

Development Summary ( Step-by-Step )

  1. Get a template, I grabbed mine from here ( office.microsoft.com ).
    ** I only used the first sheet and deleted all the sample data
  2. Create a new ASP.NET 3.5 Web Application projecct
  3. Download NPOI binaries and include in your project
  4. Build a UI that will be used to populate your template.
    ** This could also be populated by a data sources (db, XML, etc..)
    ** NOTE:  I used Excel to create the form using Excel formulas
  5. Add some c# code “magic” to load data into the template using NPOI

Sounds simple because it is… Here is the code to add the form contents into the Excel template.

// Open Template
FileStream fs = new FileStream(Server.MapPath(@"\template\Template_EventBudget.xls"), FileMode.Open, FileAccess.Read);

// Load the template into a NPOI workbook
HSSFWorkbook templateWorkbook = new HSSFWorkbook(fs, true);

// Load the sheet you are going to use as a template into NPOI
HSSFSheet sheet = templateWorkbook.GetSheet("Event Budget");

// Insert data into template
sheet.GetRow(1).GetCell(1).SetCellValue(EventName.Value);  // Inserting a string value into Excel
sheet.GetRow(1).GetCell(5).SetCellValue(DateTime.Parse(EventDate.Value));  // Inserting a date value into Excel

sheet.GetRow(5).GetCell(2).SetCellValue(Double.Parse(Roomandhallfees.Value));  // Inserting a number value into Excel
sheet.GetRow(6).GetCell(2).SetCellValue(Double.Parse(Sitestaff.Value));
sheet.GetRow(7).GetCell(2).SetCellValue(Double.Parse(Equipment.Value));
sheet.GetRow(8).GetCell(2).SetCellValue(Double.Parse(Tablesandchairs.Value));
sheet.GetRow(12).GetCell(2).SetCellValue(Double.Parse(Flowers.Value));
sheet.GetRow(13).GetCell(2).SetCellValue(Double.Parse(Candles.Value));
sheet.GetRow(14).GetCell(2).SetCellValue(Double.Parse(Lighting.Value));
sheet.GetRow(15).GetCell(2).SetCellValue(Double.Parse(Balloons.Value));
sheet.GetRow(16).GetCell(2).SetCellValue(Double.Parse(Papersupplies.Value));
sheet.GetRow(20).GetCell(2).SetCellValue(Double.Parse(Graphicswork.Value));
sheet.GetRow(21).GetCell(2).SetCellValue(Double.Parse(Photocopying_Printing.Value));
sheet.GetRow(22).GetCell(2).SetCellValue(Double.Parse(Postage.Value));
sheet.GetRow(26).GetCell(2).SetCellValue(Double.Parse(Telephone.Value));
sheet.GetRow(27).GetCell(2).SetCellValue(Double.Parse(Transportation.Value));
sheet.GetRow(28).GetCell(2).SetCellValue(Double.Parse(Stationerysupplies.Value));
sheet.GetRow(29).GetCell(2).SetCellValue(Double.Parse(Faxservices.Value));
sheet.GetRow(33).GetCell(2).SetCellValue(Double.Parse(Food.Value));
sheet.GetRow(34).GetCell(2).SetCellValue(Double.Parse(Drinks.Value));
sheet.GetRow(35).GetCell(2).SetCellValue(Double.Parse(Linens.Value));
sheet.GetRow(36).GetCell(2).SetCellValue(Double.Parse(Staffandgratuities.Value));
sheet.GetRow(40).GetCell(2).SetCellValue(Double.Parse(Performers.Value));
sheet.GetRow(41).GetCell(2).SetCellValue(Double.Parse(Speakers.Value));
sheet.GetRow(42).GetCell(2).SetCellValue(Double.Parse(Travel.Value));
sheet.GetRow(43).GetCell(2).SetCellValue(Double.Parse(Hotel.Value));
sheet.GetRow(44).GetCell(2).SetCellValue(Double.Parse(Other.Value));
sheet.GetRow(48).GetCell(2).SetCellValue(Double.Parse(Ribbons_Plaques_Trophies.Value));
sheet.GetRow(49).GetCell(2).SetCellValue(Double.Parse(Gifts.Value));

// Force formulas to update with new data we added
sheet.ForceFormulaRecalculation = true;

// Save the NPOI workbook into a memory stream to be sent to the browser, could have saved to disk.
MemoryStream ms = new MemoryStream();
templateWorkbook.Write(ms);

// Send the memory stream to the browser
ExportDataTableToExcel(ms, "EventExpenseReport.xls");

Here are the screen shots of the form and completed template…

Here is demo UI.
NPOI - ASP.NET Form used to populate a Excel Template
Here is a populated template.
NPOI - ASP.NET Form merged with Excel template

Here is a copy of the XLS file created in the program:  NPOI – ASP.NET Form merged with Excel template

Here is a copy of the source code for the demo:  NPOI – Visual Studio 2008 (ASP.NET 3.5) Template Merge Demo

** There was a caveat during the development process.  During the demo I found a bug with NPOI opening my XLS file and I had to download the source code and make two changes to get NPOI to open my XLS template (bug states this issue is caused when you save a XLSX file as XLS in Excel 2007). Read this post to see the fix or use the DLLs for NPOI included in my demo project.

** NPOI is a active Open Source project, the bugs found have probably already been fixed and if you download the latest code from CodePlex, you’ll probably have no problems running the demo.

NPOI and the Excel 2003 row limit

I ran into a problem today, testing my new NPOI DataTable web export function… While running some large queries that resulted in 65K+ rows of data, my function blew up. As you know, Excel 2003 and the BIFF format only support 65,536 rows! To make sure this never happens again, I’ve added a little block of code around my details loop to create an additional sheet every time you reach row 65,536.

code excerpt based on using a DataTable as your data source
int rowIndex = 1;               // Starting Row (0 = Header)
int sheetIndex = 1;             // Starting sheet is always set to "Sheet1"
const int maxRows = 65536;      // Max rows p/sheet in Excel 2003

// Start loop of details to write to sheet
foreach (DataRow row in DataTableToExport.Rows)
{
	// Check if max rows hit, if so start new sheet and copy headers from current sheet.
	if(rowIndex % maxRows == 0)
	{
		// Auto size columns on current sheet
		for (int h = 0; h < headerRow.LastCellNum; h++)
		{
			sheet.AutoSizeColumn(h);
		}

		// Increment sheet counter
		sheetIndex++;

		// Create new sheet
		sheet = workbook.CreateSheet("Sheet" + sheetIndex);

		// Create header on new sheet
		HSSFRow additionalHeaderRow = sheet.CreateRow(0);

		// Copy headers from first sheet
		for (int h = 0; h < headerRow.LastCellNum; h++)
		{
			HSSFCell additionalHeaderColumn = additionalHeaderRow.CreateCell(h);
			additionalHeaderColumn.CellStyle = headerRow.GetCell(h).CellStyle;
			additionalHeaderColumn.SetCellValue(headerRow.GetCell(h).RichStringCellValue);
		}

		rowIndex = 1;
	}

	// Create new detail row in sheet
	HSSFRow dataRow = sheet.CreateRow(rowIndex);
	// Loop the columns from the DataRow and add using dataRow.CreateCell(#)....
}

In a nutshell, I create some counters before going into the detail row loop to track the Row and Sheet number. When I hit the max Row number number on a sheet, I create a new Sheet. To keep everything pretty, I copy the header row from the first sheet to the first row of the new sheet. The only output limitation now is the max sheets of 255.

Build beautiful XLS documents in .NET with NPOI

I’ve seen Excel used for a ton of different solutions; Flow Charts, Business Forms, EDI, Photo Album, etc… Regardless of how Excel is being used, it’s one of the most common business document formats I know.  We commonly refer to Excel as duct tape, in the office.  I’ve traditionally limited my web & Excel integration to the capabilities of the System.Data.OleDb namespace. This has been a great solution, and when you can’t buy 3rd party controls or run code in full trust, it’s a proven solution. This has solved 99% of my problems, but there’s always been a need to do a bit more than use Excel as a basic data source.  Fortunate for me, I found a trail of posts in StackOverflow that lead me to NPOI.  It is a .NET implementation of the Apache POI Project.  NPOI is a bit behind POI, but this amazing library gives you the ability to develop rich Excel with a easy to use API.

I’ve run into a few bugs since starting, but I found lots of posts on CodePlex where the project is hosted.  I’ve found that running 1.2.2 (alpha) solves a bunch of bugs I immediately found when running 1.2.1.  I downloaded the latest build from CodePlex, but it was still on a 1.2.1 branch and was missing some of the 1.2.2 fixes.

Now that we know what NPOI is going to provide us, lets go grab the files we’ll need to get started.

  1. NPOI.Util Basic assistant class library
  2. NPOI.POIFS OLE2 format read/write library
  3. NPOI.DDF Drawing format read/write library
  4. NPOI.SS Formula evaluation library
  5. NPOI.HPSF Summary Information and Document Summary Information read/write library
  6. NPOI.HSSF Excel BIFF format read/write library

To keep the demo easy to follow and provide some good ways to refactor NPOI into your existing project, I’ve taken a old function that would output a DataTable to a HTML formatted document with an Excel (xls) extension.  This solution has worked for years, but every time you open one of these XLS files you get the following message (“The file you are trying to open “”, is in a different format than specified by the file extension. Verify that the file is not corrupted and is from a trusted source before opening the file. Do you want to open the file now?“).  It’s a bit annoying and scary to the user, but this approach was used to solve the problem of Excel truncating leading zero’s in numeric data (e.g. 00002345).

Before NPOI Function (DataTable to HTML document saved with a XLS extension)
/// <summary>
/// Exports a DataTable as a HTML formatted table and forces the results to be downloaded in a .HTM file.
/// </summary>
/// <param name="dataTable">DataTable</param>
/// <param name="fileName">Output File Name</param>
static public void DataTableToHtmlXLS(DataTable dataTable, string fileName)
{
	//Add _response header
	HttpResponse response = HttpContext.Current.Response;
	response.Clear();
	response.ClearHeaders();
	response.AddHeader("content-disposition", string.Format("attachment;filename={0}.xls", fileName));
	response.ContentEncoding = Encoding.Default;
	response.Charset = String.Empty;
	response.ContentType = "text/HTML";

	DataGrid dataGrid = new DataGrid();
	dataGrid.EnableViewState = false;
	dataGrid.DataSource = dataTable;
	dataGrid.DataBind();

	StringWriter sw = new StringWriter();
	HtmlTextWriter hw = new HtmlTextWriter(sw);

	dataGrid.RenderControl(hw);
	response.Write(sw.ToString());

	response.End();
}
Error opening HTML file saved as XLS

** If you were to look at the the XLS file in notepad, you’d see the contents are HTML.

NPOI Function (DataTable to Excel)
/// <summary>
/// Render DataTable to Excel File
/// </summary>
/// <param name="sourceTable">Source DataTable</param>
/// <param name="fileName">Destination File name</param>
public static void ExportDataTableToExcel(DataTable sourceTable, string fileName)
{
	HSSFWorkbook workbook = new HSSFWorkbook();
	MemoryStream memoryStream = new MemoryStream();
	HSSFSheet sheet = workbook.CreateSheet("Sheet1");
	HSSFRow headerRow = sheet.CreateRow(0);

	// handling header.
	foreach (DataColumn column in sourceTable.Columns)
		headerRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName);

	// handling value.
	int rowIndex = 1;

	foreach (DataRow row in sourceTable.Rows)
	{
		HSSFRow dataRow = sheet.CreateRow(rowIndex);

		foreach (DataColumn column in sourceTable.Columns)
		{
			dataRow.CreateCell(column.Ordinal).SetCellValue(row[column].ToString());
		}

		rowIndex++;
	}

	workbook.Write(memoryStream);
	memoryStream.Flush();

	HttpResponse response = HttpContext.Current.Response;
	response.ContentType = "application/vnd.ms-excel";
	response.AddHeader("Content-Disposition", string.Format("attachment;filename={0}", fileName));
	response.Clear();

	response.BinaryWrite(memoryStream.GetBuffer());
	response.End();
}

** Pretty simple right?  In my production code this is actually split into multiple functions so I can reuse the DataTable to Excel code.  The output of this function is a Excel 2003 (XLS) BIFF.

Now that we are using NPOI to create “real” XLS documents, we can do something cool like add formatting to our header row.

// handling header.
foreach (DataColumn column in sourceTable.Columns)
{
	// Create New Cell
	HSSFCell headerCell = headerRow.CreateCell(column.Ordinal);

	// Set Cell Value
	headerCell.SetCellValue(column.ColumnName);

	// Create Style
	HSSFCellStyle headerCellStyle = workbook.CreateCellStyle();
	headerCellStyle.FillForegroundColor = HSSFColor.AQUA.index;
	headerCellStyle.FillPattern = CellFillPattern.SOLID_FOREGROUND;

	// Add Style to Cell
	headerCell.CellStyle = headerCellStyle;
}
Adding Color Headers to POI Excel File

There is a million more formatting options possible and by the time you read this you should find a few more example on my site.

Reset Network Password in C#

If you have a small portal at work and need to provide a way for people to reset their password(s) or have certain authorized people reset password(s), here is a easy solution. In addition to the password reset, I also unlock the account since they have probably locked the account from trying to log in with the wrong password a million times!

Before you start, you need to know a few things first. Use Microsoft’s Active Directory Users and Computers (“ADUC”) Administrator tool on a Domain Controller to find these facts.

  1. Domain Name (ADUC)
    e.g. microsoft.local and MICROSOFT
  2. Domain Controller Name (ADUC, look under Domain Controllers)
  3. User Container (e.g. Item where all your users are located, default is “Users”)

In the example below, the company local domain is “MICROSOFT.COM” and the pre-Windows 2000 name is “MICROSOFT”. My domain controller is called “SERVER1” and all my users are in the default “USERS” container.

// Import the following namespace
using System.DirectoryServices;

        /// <summary>
        /// Reset a user's domain password, using a domain administrators account.
        /// </summary>
        /// <param name="acct">User who needs a password reset.</param>
        /// <param name="username">Administrator User Name</param>
        /// <param name="password">Administrator Password</param>
        /// <param name="newpassword">User's new password</param>
        public void resetPassword(string acct, string username, string password, string newpassword)
        {

            try
            {
                // LDAP Connection String
                string path = "LDAP://SERVER1/OU=USERS,DC=MICROSOFT,DC=LOCAL";

                // Prefix to Add to User Name (e.g. MICROSOFT\Administrator)
                string Domain = "MICROSOFT\\";  //Pre-Windows 2000 Name

                // Establish LDAP Connection
                DirectoryEntry de = new DirectoryEntry(path, Domain + username, password, AuthenticationTypes.Secure);

                // LDAP Search Filter
                DirectorySearcher ds = new DirectorySearcher(de);
                ds.Filter = "(&(objectClass=user)(|(sAMAccountName=" + acct + ")))";

                // LDAP Properties to Load
                ds.PropertiesToLoad.Add("displayName");
                ds.PropertiesToLoad.Add("sAMAccountName");
                ds.PropertiesToLoad.Add("DistinguishedName");
                ds.PropertiesToLoad.Add("CN");

                // Execute Search
                SearchResult result = ds.FindOne();

                string dn = result.Properties["DistinguishedName"][0].ToString();

                DirectoryEntry uEntry = new DirectoryEntry("LDAP://" + dn, username, password);

                uEntry.Invoke("SetPassword", new object[] { newpassword });  //Set New Password
                uEntry.Properties["LockOutTime"].Value = 0;  //Unlock Account
                uEntry.CommitChanges();
                uEntry.Close();

            }
            catch (Exception e)
            {
                // Log Error
            }
        }

The function above does all the work, but this probably won’t work by default since IIS is normally run under a low privileged local account. In order to change somebody’s password you need to use Impersonate a Domain Administrator’s account to have this capability.

** Important note, if your admin accounts are stored with your user accounts then this code could be used to reset your admin password! This is a big NO-NO since it could effectively lock you out of the network. Consider putting your users in a different container/OU and setting the filter to only look in this one place!

Convert JSON to HTML using JavaScript

So you’ve just called your first REST service and have JSON array full of data… Where do you put it? I noticed lots of people using various plug-ins to create HTML tables by defining columns, data types, etc… but what happens when you don’t know this? Since I wanted to throw random JSON data into HTML tables, I created two helper functions that will iterate over the data to create the views.

This code below is an improvement to my ad-hoc JavaScript solution I created a few weeks ago for a ASP.NET project, link below. As you will see below, it’s pretty easy to render a HTML table from a object array using plain JavaScript. Since most results are in a Table or Detail layout, I created 2 functions to return the data in either format. I also added some optional parameters that you can set to control formatting. The Details View was designed to show a single row/object, the headers will display on the left and the data will display on the right (see second example).

// This function creates a standard table with column/rows
// Parameter Information
// objArray = Anytype of object array, like JSON results
// theme (optional) = A css class to add to the table (e.g. <table class="<theme>">
// enableHeader (optional) = Controls if you want to hide/show, default is show
function CreateTableView(objArray, theme, enableHeader) {
    // set optional theme parameter
    if (theme === undefined) {
        theme = 'mediumTable'; //default theme
    }

    if (enableHeader === undefined) {
        enableHeader = true; //default enable headers
    }

    // If the returned data is an object do nothing, else try to parse
    var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;

    var str = '<table class="' + theme + '">';

    // table head
    if (enableHeader) {
        str += '<thead><tr>';
        for (var index in array[0]) {
            str += '<th scope="col">' + index + '</th>';
        }
        str += '</tr></thead>';
    }

    // table body
    str += '<tbody>';
    for (var i = 0; i < array.length; i++) {
        str += (i % 2 == 0) ? '<tr class="alt">' : '<tr>';
        for (var index in array[i]) {
            str += '<td>' + array[i][index] + '</td>';
        }
        str += '</tr>';
    }
    str += '</tbody>'
    str += '</table>';
    return str;
}

// This function creates a details view table with column 1 as the header and column 2 as the details
// Parameter Information
// objArray = Anytype of object array, like JSON results
// theme (optional) = A css class to add to the table (e.g. <table class="<theme>">
// enableHeader (optional) = Controls if you want to hide/show, default is show
function CreateDetailView(objArray, theme, enableHeader) {
    // set optional theme parameter
    if (theme === undefined) {
        theme = 'mediumTable';  //default theme
    }

    if (enableHeader === undefined) {
        enableHeader = true; //default enable headers
    }

    // If the returned data is an object do nothing, else try to parse
    var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;

    var str = '<table class="' + theme + '">';
    str += '<tbody>';

    for (var i = 0; i < array.length; i++) {
        var row = 0;
        for (var index in array[i]) {
            str += (row % 2 == 0) ? '<tr class="alt">' : '<tr>';

            if (enableHeader) {
                str += '<th scope="row">' + index + '</th>';
            }

            str += '<td>' + array[i][index] + '</td>';
            str += '</tr>';
            row++;
        }
    }
    str += '</tbody>'
    str += '</table>';
    return str;
}

Standard Table Example Usage:

$(document).ready(function() {
	$.ajax({
		type: "POST",
		url: "/SampleRestService",
		contentType: "application/json; charset=utf-8",
		dataType: "json",
		data: "{}",
		success: function(res) {
			$('#Results').append(CreateTableView(res)).fadeIn();
		}
	});
});
JSON to HTML Table - Standard View

Details View Example Usage:

$(document).ready(function() {
	$.ajax({
		type: "POST",
		url: "/SampleRestService",
		contentType: "application/json; charset=utf-8",
		dataType: "json",
		data: "{}",
		success: function(res) {
			$('#Results').append(CreateDetailView(res,"CoolTableTheme",true)).fadeIn();
		}
	});
});
JSON to HTML Table - Details View

JSON to HTML JavaScript Source Code

That’s it, just do you normal jQuery ajax call and you can put your JSON into a HTML Table. This is a great way to test your JSON objects. I’ve tested the JSON to HTML on various object(s) and the results have been pretty good. If you find you need advanced features when your building your HTML table, you should look at something like jqGrid that has paging, sorting, etc…

[Update 10/6/2010]
A lot of people have asked for a full working HTML demo using JSON strings. The link below is a demo showing how to use the helpers with various JSON strings. Let me know if this helps!

JSON to HTML – Complete HTML Demo Project

Show a List of Posts for a Category on your 404 page

Today is my second day of being back online since moving hosts to GoDaddy from WebHost4Life. I would like to say the process was painless, but I had to call tech support at GoDaddy 5 times to get my hosting account setup right (Win Web vs. Windows). This undocumented but important configuration settings, will determine if you can or cannot run PHP on Windows at GoDaddy. So if you plan to sign-up for a Windows account and to run a PHP application (like WordPress), then make sure you call and order a “NON-GRID” account…

Now that things are back up and running I’ve noticed that I’m getting lots of hits on my old permalinks. I had some problems in moving things off my old host since each button click on their site would take 3-5 minutes (and time out 90% of the time). To help track what was happening, I set my 404 to go to WordPress’s “index.php” so I could track the hits and throw a pretty 404 message. After getting something setup, I decided I wanted to show a list of my posts so the user could quickly find what they are looking for. Since people only hit my Web Development posts, I inserted the logic below into my 404.php using the WordPress Editor under Appearance.

<?php
	$out = '';

	$query = array();

	$query[] = 'category=web development';
	$query[] = 'numberposts=100';

	$posts_to_show = get_posts( implode( '&', $query ) );

	$out = '<ul>';

	foreach ($posts_to_show as $post_to_show) {
		$permalink = get_permalink( $post_to_show->ID );
		$out .= <<<HTML
		<li>
			<a href ="{$permalink}" title="{$post_to_show->post_title}">{$post_to_show->post_title}</a>
		</li>
HTML;
	}

	$out .= '</ul>';

    echo $out;
?>

This little snipped is based on the WP Show Post Shortcode. I basically hard coded the query category and set the number of result to 100. This results in a list of my last 100 blog posts, sorted by date posted.

If you want to see it in action, type in a invalid URL to my site and you’ll get a 404 with a list of links to my blog posts!

Note… This is not going to help with search engine rankings because it’s a 404 error page. My goal was to give the lost visitor quick access to my development posts, since I’m 99% sure they used an old link indexed by Google.

ASP.NET JSON Response to Dynamic HTML Table

Do you need a way to quickly display a HTML table of data from a JSON response, I got a solution. The key to doing all this is just a little JavaScript to parse your JSON results. By looping over the array of objects, you can build a dynamic table (no predefined columns) in just a few seconds. This solution can be used for any language, since I use .NET / jQuery most of my day, this is a ASP.NET demo.

If you just want to see a full working demo, download the sample project at the bottom of the article. It’s a VS 2008 project build-ready!

This user control was an enhancement to an existing user control whose core functionality is to take a user supplied T-SQL statement and generate a nicely formatted HTML table. The existing control has worked great for years, but since I recently moved my code from 2.0 to 3.5, I figured I’d give this module a little attention. I found pages using the module to sometimes take 15+ seconds to load because of slow database servers. I enabled caching to try and work around the problem, but users told me that some queries need to be real-time. The solution was to move from a standard GridView control to a AJAX jQuery solution that would pulled the data and convert the results to a pretty HTML table. I used Google to search for a existing solution, but everything I found used 3rd party components or required a results (defined columns) template (e.g. Name and Object[i].Name). Since my tool is designed for ad-hoc queries, I wanted the rendering logic to require no predefined facts about the data.

My demo has 3 external requirements, which are all FREE (jQuery, JavaScript JSON helper, JSON.NET).

Newtonsoft.Json.dll
jquery-1.3.2.debug.js
json.debug.js

In addition to these requirements, I added a few layout files to the demo to make the HTML table look nice. Nobody likes a ugly demo…

images / loading.gif
styles / default.css

The only thing left was the results page, rendering JS logic and the web service.

Here is the JavaScript function used to convert a JSON array of objects into an HTML table.

function CreateDynamicTable(objArray) {
    var array = JSON.parse(objArray);

    var str = '<table class="lightPro">';

    str += '<tbody><tr>';

    for (var index in array[0]) {
        str += '<th scope="col">' + index + '</th>';
    }

    str += '</tr>';

    str += '</tbody><tbody>';

    for (var i = 0; i &lt; array.length; i++) {
        str += (i % 2 == 0) ? '<tr class="alt">' : '</tr><tr>';

        for (var index in array[i]) {
            str += '<td>' + array[i][index] + '</td>';
        }

        str += '</tr>';
    }

    str += '</tbody>'

    str += '</table>';

    return str;
}

Pretty simple, right… I pass in an object array that I iterate over to grab all the row/column values. I use the first row to grab the column names and place them inside the table header.

[Update 4/30/10] – I created 2 function that are improvements on this in a new posting. Check it out to see example use and download the JS code. Much better solution than hard-coding the values. Read Now…

Here is the actual page that makes web service call and returns displays the HTML table.

<script src="scripts/jquery-1.3.2.debug.js" type="text/javascript"></script>
<script src="scripts/json.htmTable.js" type="text/javascript"></script>
<script src="scripts/json.debug.js" type="text/javascript"></script>

<script type="text/javascript">
        $(document).ready(function() {
            $.ajax({
                type: "POST",
                url: "DemoSvc.asmx/GetJSONTableContents",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                data: "{}",
                success: function(res) {
                    $('#<%= DynamicGridLoading.ClientID %>').hide();
                    $('#<%= DynamicGrid.ClientID %>').append(CreateDynamicTable(res.d)).fadeIn();
                }
            });
        });
</script>

<form id="form1">

<div id="DynamicGrid">
<div id="DynamicGridLoading">
            <img src="images/loading.gif" alt="" /><span> Loading Data... </span></div>
</div>

</form>

The code is pretty simple and there is no code behind, everything is done in the web service and injected via jQuery. The could have be done in a HTML page or any other language, nothing specific to ASP.NET right here.

The code for the web service is pretty basic, just be sure to look at the Service() method that is used to convert the DataTable to JSON. This is where the magic happens. This method is a wrapper to the JSON.NET library and chooses some default settings needed for the conversion.

In summary, this little switch removed the the blocking being caused by my slow SQL queries. My pages now instantly load **POOF**. During loading, they display a loading icon/text so the users know something is loading! Since caching was already being used for some queries, I change the code to cache the DataTable in the web service call.

VS2008 – ASP.NET DataTable to JSON to Dynamic HTML Table Demo

T-SQL Stored Procedure (Optional Parameters)

I use a lot of queries to drive reports and interactive search tools and the most common requirement of all my queries is optional parameters. I’ve used a ton of different methods to pull this off in the past, but I primarily use one approach when I build stored procedures that will be used with optional parameters that is efficient and easy to read.

-- //////////////////////////////////////////
-- Stored Procedure - Optional Params (NEW WAY)
-- //////////////////////////////////////////
CREATE PROCEDURE GetOrders
	@OrderNumber VARCHAR(10),
	@TrackingNumber VARCHAR(10)
AS
	SELECT * FROM SALES
	WHERE (@OrderNumber IS NULL OR @OrderNumber = '' OR ORDERNUMBER = @OrderNumber)
		AND (@TrackingNumber IS NULL OR @TrackingNumber = '' OR TRACKINGNUMBER = @TrackingNumber)

-- //////////////////////////////////////////////////
-- Stored Procedure - Optional Params - Dynamic SQL (OLD WAY)
-- //////////////////////////////////////////////////
CREATE PROCEDURE GetOrders
	@OrderNumber VARCHAR(10),
	@TrackingNumber VARCHAR(10)
AS
	DECLARE @STRSQL VARCHAR(200)
	SET @STRSQL = 'SELECT * FROM SALES WHERE 1=1 '

	IF @ROBINCODE <> ''
	BEGIN
		SET @STRSQL = @STRSQL + ' AND ORDERNUMBER = ''' + @OrderNumber + ''''
	END

	IF @DELTOCODE <> ''
	BEGIN
		SET @STRSQL = @STRSQL + ' AND TRACKINGNUMBER = ''' + @TrackingNumber + ''''
	END

EXECUTE(@STRSQL)

As you can see, the “New Way” has a lot less code and does not use dynamic T-SQL. In addition to checking for NULL parameter values, I also suggest you check for empty strings since text boxes normally return an empty string.

Now you have the choice of sending NULL or “” and the criteria will be skipped.

Download Your Site to HTML

HTTrack website copier is awesome and FREE! I’ve been using it for a few months and I’ve already saved myself and my team members hundreds of hours by downloading full working copies of various websites locally.

Here are a few examples of websites I download.

  1. A client was having problems with their hosting company who refused to give them access to their source code (developed by a 3rd party) to their CF website. After weeks of trying to solve the problem, they decided to switch hosting companies. During their migration to a hosting company and a new CMS solution, they wanted to keep a copy of the old site online. Regardless of the engine running the website, HTTrack was able to download a working copy of the site to HTML, minus the dynamic features (Search, CMS Admin, etc…) in a few minutes.
  2. We inherited a old web server at working running Plone 2.0.4. The machine was running on old hardware that was failing (2/3 dead HDD, broken RAID 1) and Zope was randomly crashing. After spending 3 days trying to get the machine stable, I decide to convert the site to HTML and put on one of our newer “stable” web servers. The process was a little mess, since our plone instance pointed to folders paths vs. actual files (/index_html vs /index.hmtl) the final static site had a lot of weird and randomly directed links! The final static HTML site probably took ~8 solid hours of HTML clean-up, but there was also a lot of bad/obsolete content in the existing portal that made this process painful!
  3. I have a few websites I like to use as samples/demo that show better as interactive! Using HTTrack and controlling the depth of link following/downloading (like first page only), I can download an offline working copy of a sites main page! This is a great way to demo a feature/capability/competitor website…

A few other good things to know, a couple sites I’ve downloaded require you to login first. This isn’t an issue with HTTrack, since you can build your own cookies to apply to your capture. It was a bit tricky getting the cookie format correct (Used Netscape Cookie Format), but after a few minutes I was able to take the cookie data from IE/FireFox and have a perfect working cookie for HTTrack to use!

Once again, this is FREE utility that is handy to have around!

HTTrack WEBSITE COPIER

SubSonic 2.2 – RESTHandler (Add ProviderName Support)

I’ve been using SubSonic’s built-in RESTHandler for some basic AJAX features in my portal at work. This is a really nice extra feature, and provides a quick way to pull xml/json/rss from your DAL. I noticed that a few features based on this handler had stopped working a few weeks ago. I found that SubSonic’s RESTHandler had no way to pass in the provider name as part of the url. I currently have 5 different providers (databases) setup for SubSonic, so I needed a way to point to the various providers when calling a URL.

Edit the following file “SubSonic/HttpHandlers/RESTfullUrl.cs”

1. Add new property to access “ProviderName”

private string _providerName = String.Empty;
public string ProviderName
{
get { return _providerName; }
set { _providerName = value; }
}

2. Modify ParseURL()

private void ParseUrl()
{
//work backwards up the URL
//first thing, check for a query string and strip it
string workingUrl = _rawUrl;

if(workingUrl.Contains("?"))
{
//strip off the query string - it'll be used later
workingUrl = Strings.Chop(workingUrl, "?");

}

string[] bits = workingUrl.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries);
//the URL should be split out into
//protocol ("http");
//domain ("foo.com");
//service directory ("services");
//provider name ("northwinds")
//table or sp ("products")
//command.format ("list.xml")

//the index of each item within the URL
int commandIndex = bits.Length - 1;
int tableSPIndex = bits.Length - 2;
int providerIndex = bits.Length - 3;

//now check to see if the last item on the URL is a key, or
if(IsNonKeyCommand(workingUrl))
{
//the last item is the command - list/show/etc
//set it
//the last item is a key, set it, and then the command
_key = Path.GetFileNameWithoutExtension(bits[bits.Length - 1]);
commandIndex--;
tableSPIndex--;
providerIndex--;
}

//the command is the next item up the chain
_restCommand = DecideCommand(Path.GetFileNameWithoutExtension(bits[commandIndex]));

//evaluate the command
if(_restCommand == RESTCommand.Exec)
_spName = bits[tableSPIndex];
else
_tableName = bits[tableSPIndex];

_providerName = bits[providerIndex];

ParseQueryString();
}


Edit the following file “SubSonic/HttpHandlers/RESTHandler.cs”

3. Update GenerateReturnSet(), line #286.

q = new Query(_url.TableName);  //before
q = new Query(_url.TableName,_url.ProviderName);  //after


Here is an example using the new syntax that supports provider name.

http://localhost/services/northwinds/customers/list.xml