Thursday, August 28, 2008

Unit Testing Saves the Day

I had a fantastic unit testing experience at work today. A couple of days ago I released a DLL to production that scans some text and transforms part of the text according to certain rules. An example of this would be the text that users enter into a forum post. Users would enter [b]some text[/b] and the text processor would transform that into <b>some text</b> before writing it out to a web page.

When writing the transform DLL I created several unit test that check every possibility that I could think of especially the edge cases. It was a great aid and tool to developing a robust and well tested DLL.

Inevitably as soon as it was release there an edge case came to light that I hadn't thought of and so I had to fix the "bug" in the DLL. Finding and fixing it was an absolute pleasure.

First off I took the block of text that demonstrated the bug and created a unit test that passed this block of text to the DLL and showed that the DLL was failing. At this point I haven't touched the errant transform code. I ran all the unit tests in the solution (takes about 5 seconds) and as expected they all passed the unit test except for the new one.

I then proceeded to fix the code and when done I reran all the unit tests again. This time the new test passed. This is called red/green testing. First you see the red light because it failed. You fix the code. Then you see the green light. I believe that Scott Hanselman says that it's called grey/grey testing if you're color blind.

This approach gave me an enormous amount of confidence to release the new DLL because I know that I haven't introduced any code that will break any of the previous standard and edge cases because I've tested them all again - and in only 5 seconds. Granted that it took me several hours to write all those tests but I would have probably spent at least 2 hours retesting this DLL after this fix had I not had the unit tests to do it for me.

I consider this a great victory for unit testing and test driven development and I am finally seeing my efforts in writing unit tests pay off in time saved and robust software.

Tuesday, August 26, 2008

Stack Overflow

I've been using the Beta version of Stack Overflow and I'm very impressed. Jeff Atwood and his team have done an excellent job with this site and it's already provided me with some answers to questions that I had and those answers were furiously fast and accurate. I hope the quality and speed continues when they go live.

I've just caught up with the Hansel Minutes podcasts so I've started listening to Stack Overflow's podcasts. I've listened to the first 3 so far. To start with I wasn't that excited by them but by the end of the 3rd podcast they've started to grow on me and I can see myself listening to them on a regular basis.

Talking of podcasts for programmers, my friend and co-worker Saul Mora has just published a list of techie podcasts that he listens to.

Stop Forum Spam

I'm impressed with a site that my friend Huw Reddick recently alerted me to called Stop Forum Spam. It's a database of IP's, user name's and emails that have been used to spam forums. If you run a forum or maintain forum software then it's a great resource to query when someone's registering on your forum to try and cut down on spammers joining your forum. You can also submit spammer information to their database (manually) at this link. If, however, you're like me and hate spammers but are also very lazy then you'll want to automate this process as much as possible. Here's some C# code that will submit the spammers info for you:

        public bool SubmitForumSpammer(string ip, string username, string email, string apikey)
        {
            WebRequest req = WebRequest.Create("http://www.stopforumspam.com/add");
            string postData = String.Format("username={0}&email={1}&ip_addr={2}&api_key={3}", username, email, ip, apikey);

            byte[] send = Encoding.Default.GetBytes(postData);
            req.Method = "POST";
            req.ContentType = "application/x-www-form-urlencoded";
            req.ContentLength = send.Length;

            Stream sout = req.GetRequestStream();
            sout.Write(send, 0, send.Length);
            sout.Flush();
            sout.Close();

            WebResponse res = req.GetResponse();
            StreamReader sr = new StreamReader(res.GetResponseStream());
            string returnvalue = sr.ReadToEnd();

            return returnvalue.Contains("Data submitted successfully");
        }
 

Thursday, August 21, 2008

Unable to cast object of type 'System.Int32' to type 'System.String'

Came across an interesting situation today with the error message:  System.InvalidCastException: Unable to cast object of type 'System.Int32' to type 'System.String'

I couldn't work out how you couldn't cast an Int32 to a string? Seems impossible doesn't it?

Try this little snippet of code and you will be able to get that error:

            Hashtable groupList = new Hashtable();
            groupList.Add(11, new object());
            groupList.Add("12", new object());
            List<int> groups = groupList.Keys.Cast<string>().Select(a => Convert.ToInt32(a)).ToList();

The Hashtable accepts a string as a key in the second Add() call so it now has both int's and strings as keys. What I'm guessing though is that on a call to Add() the Hastable checks what data type for the key is. On the first call this data type is unset so it takes the data type of the first param and uses that as the data type for the key. On subsequent calls to Add() it sees that the data type for the key is set so just adds the item as an object for the key. This is just my guess and I'm sure if I took the time to look at this member function in Reflector I'd find out if I'm right or not.

Tuesday, August 19, 2008

Hashtable keys intersect with list of Int32

The problem: You have a classic Hashtable. Although the keys are strings they hold only ints. You also have a list of ints. You want to find out if any of the keys from the Hashtable are in the list of ints. How do you do this in one line of LINQ?

The solution, using LINQ, that I came up with is:

            // Setup the test data
            System.Collections.Hashtable ht = new System.Collections.Hashtable();
            ht.Add("1", new object());
            ht.Add("2", new object());

            List<int> second = new List<int>();
            second.Add(2);
            second.Add(3);

            // Query the data
            bool containsKey = ht.Keys.Cast<string>().Select(a => Convert.ToInt32(a)).ToList().Intersect(second).Count() > 0;

            // Print the result
            Console.Write("Contains Key: {0}", containsKey);
 

Monday, August 18, 2008

Startup Weekend Phoenix

Ever heard of Startup Weekend? I hadn't until just recently but there's one coming to Phoenix from 17-19 October 2008 and I've just ponied up my $40 to spend my entire weekend working on a startup. Should be interesting - I'm very excited:

http://phoenix.startupweekend.com/

Will take place at:

Gangplank HQ Offices
325 E Elliot Rd, Suite 34
Chandler, AZ 85225

Saturday, August 16, 2008

DOCX to HTML via XSLT

A friend just gave me a link to Creating a docx -> Html Preview Handler for SharePoint which has the modifications necessary for the XSLT that comes with Sharepoint to make the HTML web page show images as well as text from a Word 2007 document. I have a number of documents in .docx format that I want to make available as web pages but want to keep the originals in .docx format so that I can continue to edit and modify them. It is my idea that whenever I modify a Word 2007 (docx) document that I can just dump the new file into the App_Data folder and the site's pages will start showing the new or modified content. It should be too hard to do with this template. This is a soon-to-be-done project. I'll post a link to the site once I've got this done.

Tuesday, August 12, 2008

ASP.NET MVC Preview 3 to Preview 4

I recently upgraded a project from ASP.NET MVC Preview 3 to Preview 4. Running it in Cassini showed no problems but as soon as I published it to IIS 6 I started getting this error which I have yet to solve:

You are not authorized to view this page

You do not have permission to view this directory or page using the credentials that you supplied.


Please try the following:

  • Contact the Web site administrator if you believe you should be able to view this directory or page.
  • Click the Refresh button to try again with different credentials.

HTTP Error 401.1 - Unauthorized: Access is denied due to invalid credentials.
Internet Information Services (IIS)


Technical Information (for support personnel)

  • Go to Microsoft Product Support Services and perform a title search for the words HTTP and 401.
  • Open IIS Help, which is accessible in IIS Manager (inetmgr), and search for topics titled Authentication, Access Control, and About Custom Error Messages.

Visual Studio 2008 SP1

Visual Studio 2008 SP1

Visual Studio 2008 SP1 and Microsoft Framework 3.5 SP1 is available to download.

Monday, August 11, 2008

Rube Goldberg Machine

I regularly hear Scott Hanselman refer to a Rube Goldberg Machine on his Hansel Minutes podcast and once you hear something repeated enough times you need to look it up. From wikipedia: A Rube Goldberg machine is a deliberately over-engineered apparatus that performs a very simple task in very indirect and convoluted fashion.

Now I understand why he often compares a software project to a Rube Goldberg Machine.

Phoenix Startup Weekend 17-19 October 2008

The first Phoenix Startup Weekend will be 17-19 October 2008. It looks intense (54 hours work over a weekend) but also very interesting. I've marked this on my calendar but haven't booked yet. I'm very keen on doing this although I'm guessing that I'll be shattered by the time Monday comes around and will need to go back to work to have a break.

Friday, August 8, 2008

C# boxing and unboxing

In my quest to become a C# expert I've decided that I should be able to accurately and unambiguously define each and every C# term and keyword. As such I'm going to try and create a post about each one in my own (and quoted) words to act as my own reference to this language.

Boxing and Unboxing

From the documentation: Boxing and unboxing enable value types to be treated as objects. Boxing a value type packages it inside an instance of the Object reference type. This allows the value type to be stored on the garbage collected heap. Unboxing extracts the value type from the object.

My understanding is that the Object class internally has a boolean HasValue property which if false means that this object has a "value" of null. If it's true then a value has been assigned. I also assume that there is a Type property which represents the type of object that has been stored (such as Int32) and also an area of memory for the object itself which represents the size of the object presumably obtained from the sizeof() operator.

Stuffing a value into an Object is called boxing and this is done by means of a cast:

Int32 i = 1;
Object o = (object) i;

Retrieving the value into a strongly typed type is called unboxing and this is also done using a cast:

i = (Int32) o;

Notes

Comments welcome...

Tuesday, August 5, 2008

Copy data from local table to remote database table

I need to do this every now and then and as usual forget the syntax or what I did last time to do this. I need to copy some of the data in a table to an identically structured table on another (different) database running on another Server. I do this from SQL Server Management Studio (SSMS) 2005.

  1. Using Server Objects > Linked Servers I link the remote server to my local server. (You could also connect to remote server 1 and link to remote server 2 and do this between 2 remote servers.)
  2. If the target table has an Identity key I usually disable this by setting it to no and then after the copy I set it back to yes.
  3. The syntax to copy the data is:
    insert into [255.255.255.255].dbname.dbo.tableName
    select * from dbname.dbo.tableName where ColID=[some condition]

If the "local" DB is a remote server then precede that DB name with the IP address in square brackets as well.

Another way to do the data transfer is to specify the columns after the first tableName (in parenthesis) and instead of the * (without parenthesis) and omit the identity column and let SQL Server generate that value for you if you don't need to copy it. This is the syntax:

insert into [255.255.255.255].dbname.dbo.tableName (col1, col2, col3) select col1,col2,col3 from dbname.dbo.tableName where ColID=[some condition]

Friday, August 1, 2008

type or namespace name 'ProfileCommon' could not be found

I recently hit this compile error while converting a Visual Studio web site project to a VS2008 Web App project: The type or namespace name 'ProfileCommon' could not be found (are you missing a using directive or an assembly reference?)

Turns out that Web Applications don't support the auto generation of the ProfileCommon object like web site projects do. To get this to work install this VS addin and then add it to the build process as described here.