# Wednesday, July 18, 2007

I’ve recently done some research into .NET WinForms testing on behalf of a customer and there are several different levels which we can attack this. Each is of different complexity and cost.

Simulate Mouse Clicks and Keyboard Presses

This method has been around since Windows 3.1 days and involves heavy use of SendKeys and SendMessage to manipulate Window message queue to send mouse and keyboard events directly. An old but pretty good sample is at http://msdn.microsoft.com/msdnmag/issues/02/03/Bugslayer/.

Drive Forms Controls Directly

The next simplest method is to get hold of Windows forms controls directly so you can call methods and set properties using code. This method usually involves running the target forms within your own process. The following two MSDN magazine articles describe the steps:

The second one looks at how to cancel message boxes etc by sending messages directly to the window. Both articles describe the method but they are not very user friendly and you will have to write a fair amount of code. Fortunately there is a library available that hooks into the NUnit testing framework at http://nunitforms.sourceforge.net/. Still lots of code but you get to write higher level stuff such as:

ButtonTester button = new ButtonTester("nameOfSomeButton");
button.Click();
Assert.Equals(“Clicked!”,  button.Text);

The only problem I can see with this is maybe development has stopped as the last full release was in November 2004 with a few alphas up until May 2006. Still you can grab the source and start hacking away if there are any problems.

Using Active Accessibility 2.0

This API has been around for a few years and is a standard way of controlling all Windows controls. The trouble is though that it’s a COM API and somewhat complex to master. I’ve seen anecdotes on the Internet talking about the test code being more complex than the application code when using this. For completeness the API is documented at http://msdn2.microsoft.com/en-us/library/ms697707.aspx though the following section has a more modern way of doing this. A walkthrough is available showing how to make a .NET application accessible at http://msdn2.microsoft.com/en-us/library/cb35a5fw(vs.80).aspx.

Using UI Automation

UI Automation is the successor to Active Accessibility and, unlike Active Accessibility, was specifically designed with automation in mind. It’s described in more detail at http://msdn2.microsoft.com/en-us/library/aa348551.aspx with a complete walkthrough and sample code at http://msdn.microsoft.com/msdnmag/issues/07/03/Bugslayer/default.aspx. One thing to note though – the UI Automation bits are only available on computers with .NET 3.0 installed – i.e. Vista, Windows XP and Windows Server 2003.

There is also a very useful library available to help with the code at http://www.codeplex.com/uapp.

Third Party Tools

This wouldn’t be complete without a nod to some of the commercial offerings out there. I haven’t used any since Rational Test many years ago which was next to useless but I hear reasonably good things about Mercury QuickTest Professional though I have no idea how much it costs. There is even a virtual lab available on Automating Testing of Windows Forms Application with TestComplete and Visual Studio 2005 Team System.

Conclusions

To summarize, I would recommend trying NUnitForms and UI Automation to see how you get on with both of them and making a choice between the two. QuickTest Professional will probably be too costly and the other two technologies are a lot of work and too old to consider for all your testing – they may have tactical uses though.

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Wednesday, July 18, 2007 7:52:52 AM (GMT Daylight Time, UTC+01:00)  #    Comments [1] Trackback
# Tuesday, June 19, 2007

I'm trying to get a decent solution to inserting code in blog articles so the next few posts are all about the code. The sample below is a simple line counter tool I use to work out some metrics for code reviews.

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace LineCount
{
    class Program
    {
        private static int folders;
        private static int files;
        private static int lines;
        private static int code;
        private static int comments;

        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Console.WriteLine(@"
Usage: linecount <root folder>

e.g. linecount t:\dev\projects\main

NB: Only .cs files are considered
    Review time is hard coded to 200 lines per hour
");
                return;
            }

            CountLines(new DirectoryInfo(args[0]));

            Console.WriteLine("FOLDERS:{0} FILES:{1} LOC:{2} SLOC:{3} COMMENTS:{4}", 
                folders, files, lines, code, comments);
            Console.WriteLine("Code density: {0:p}", 
                (double)code / (double)lines);
            Console.WriteLine("Comment density: {0:p}", 
                (double)comments / (double)lines);
            Console.WriteLine("Comment ratio: {0:p}", 
                (double)comments / (double)code);
            Console.WriteLine("Estimated review time: {0}h", 1+ (code / 200));
        }

        private static void CountLines(DirectoryInfo parent)
        {
            ++folders;

            foreach (DirectoryInfo folder in parent.GetDirectories())
            {
                CountLines(folder);
            }

            foreach (FileInfo file in parent.GetFiles())
            {
                CountLines(file);
            }
        }

        private static void CountLines(FileInfo file)
        {
            switch (file.Extension)
            {
                case ".cs":
                    break;
                default:
                    return;
            }

            ++files;

            using (StreamReader reader = file.OpenText())
            {
                string line = null;
                bool inComment = false;

                while ((line = reader.ReadLine()) != null)
                {
                    ++lines;
                    line = line.Trim();

                    if (line.Length == 0)
                        continue;

                    if (line.StartsWith("//"))
                    {
                        if (line.Replace("//", "").Trim().Length > 0)
                            ++comments;

                        continue;
                    }

                    if (line.StartsWith("/*"))
                        ++comments;
                    else if (!inComment)
                        ++code;

                    if (line.Contains("/*"))
                    {
                        inComment = true;
                    }

                    if (inComment && line.Contains("*/"))
                    {
                        inComment = false;
                    }
                }
            }
        }
    }
}
by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Tuesday, June 19, 2007 3:54:31 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback
# Friday, October 20, 2006

Time to clean up all the shortcuts to interesting web pages sitting around on my desktop... In no particular order:

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Friday, October 20, 2006 3:23:20 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback
# Saturday, August 26, 2006

Because of the way you assign FullTrust permissions to an InfoPath form, the correct permissions are not assigned when running the form under the Visual Studio debugger. You might see errors such as "That assembly does not allow partially trusted callers". The solution is to use a macro that ships in the InfoPath 2003 Toolkit called IPFullTrust. See the macro page for more detail.

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Saturday, August 26, 2006 11:03:19 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback
# Friday, March 24, 2006

This one had me stumped for a while, especially as I couldn't find anything with the internal knowledge search tools. The symptoms are an Excel add-in that runs perfectly on it's own but crashes when run in the Visual Studio 2003 debugger. Actually, if you enable native debugging, it crashed Visual Studio too...

It turns out that by default Microsoft Office applications try to host the most recent version of the .NET runtime. That means you can't attach a .NET 1.1 debugger if you have .NET 2.0 installed side-by-side. The details are here but you basically have three options:

  • Develop with Visual Studio 2005 and .NET 2.0
  • Use "Start Without Debugging" from VS2003 and then attach a 2.0 compatible debugger
  • Create a configuration file for the relevant office application and ensure there is only a <supportedRuntime> element for version="v1.1.4322"

Now playing: Scott Hanselman and Carl Franklin - XML Tools and Technologies

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Friday, March 24, 2006 12:23:50 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] Trackback
# Monday, February 27, 2006

For the second time I've wasted time trying to work out why the serialized output from the XmlSerializer was missing elements so it's time to write the answer here as a reminder for next time.

Basically the XmlSerializer will not output content that it can't read back in which means that any read only property will not be serialized.

This is not the case for properties that implement ICollection or IEnumerable as collections have their own serialization rules.

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Monday, February 27, 2006 4:01:09 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] Trackback
# Sunday, July 17, 2005

If you are developing Reporting Services extension assemblies that require <appSettings> elements in application configuration file (e.g. <add key="SqlConnectionString" value="Integrated Security=SSPI;Data Source=(local);" />) then you will need to modify a couple of files:

  • To design reports successfully, add the configuration to the VisualStudio app.config file
    C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE\devenv.exe.config
  • To deploy successfully, add the configuration to the ReportServer web.config file
    C:\Program Files\Microsoft SQL Server\MSSQL\Reporting Services\ReportServer\web.config
by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Sunday, July 17, 2005 2:30:43 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback
# Saturday, July 09, 2005

Microsoft Patterns and Practises have finally released the tool they use to automatically generate the resx resource files in their Enterprise Library. My thoughts on the library itself are covered elsewhere in this blog but this tool is fantastic. It's a real time saver because each string only requires a single line in the strings file and no angle brackets which is no worse than typing into your source file. Grab the zip file (you will need to join the workspace to download), install and read the docs.

On the subject of tools, don't miss Scott Hanselman's 2005 Ultimate Developer and Power Users Tool List.

Now playing: Koan Bremner - CO-010-20050703 - CrossOver Session Ten

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Saturday, July 09, 2005 12:42:12 PM (GMT Daylight Time, UTC+01:00)  #    Comments [3] Trackback
# Sunday, May 01, 2005

It's May Day Bank Holiday Weekend so I was going to try and stay away from the blog but after a testing afternoon with the new Team System Beta I thought I'd better share.

Firstly the install. I created a new Virtual PC image of Win2k3 SP1 to install the Team Foundation Server on. What the install guide doesn't tell you is that if you turn a server into a domain controller after installing Internet Services then the web won't work. You only find this out after installing SharePoint Services and following the troubleshooting guide when things don't work. After reinstalling SharePoint, Reporting Services and Internet Services things looked better and the Team Foundation install worked first time which was much better than my Beta 1 experience. However, after install, Analysis Services and Internet Services are hammering the CPU for no reason that I can determine. Installing the Visual Studio client was just as frustrating as the Beta 1 uninstall doesn’t clean up too well. After a couple of failed attempts I found this tool to clean up before installing.

Connection to the Foundation Server worked first time but failed to create a portfolio project complaining that the methodology could not be found. I haven't been able to get any further with this. The non-team bits do pretty much exactly what it says on the tin although the Intellisense is a little aggressive. The performance stuff also works well but the testing tools crashed the development environment every time I tried to run a test. This maybe due to the installation difficulties but I can't tell. Time to put it all back in the box and wait for the release I think.

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Sunday, May 01, 2005 8:03:28 PM (GMT Daylight Time, UTC+01:00)  #    Comments [2] Trackback
# Saturday, April 16, 2005
But can you wait until I’ve finished downloading it
by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Saturday, April 16, 2005 10:03:15 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback
# Saturday, March 05, 2005

This update to the original application blocks has recently been released. After a couple of weeks developing with it I’ve decided that I’m going to ditch it and go back to the old blocks. There is lots of really useful functionality but what I’ve found boils down to two main problems.

The first problem I’ve been wrestling with is the flexibility in library configuration. I applaud the flexible storage mechanism and the excellent configuration application but, having tried to add my own provider class, I think it is too complicated. You need to derive three classes for every provider – ConfigurationView, ProviderFactory and ProviderData. The equivalent code written without the Enterprise Library is about half as much.

I also wonder what the benefit of having a system administrator rework your exception handing? The whole idea of exceptions is to only catch those you are capable of handling. If your handler catches a SqlException but the configuration is changed to wrap it in a MyException then the whole thing is going to stop working. I can just imagine the support calls:

Support: “Hello, Exony support”

Customer: “Er, hello. Your application isn’t working.”

Support: “OK, well looking at the deployment logs I can see it passed it’s customer acceptance tests. Have you changed anything recently?”

Customer: “Well I used the configuration tool to modify the exception handling.”

Support: “You shouldn’t do that. It’s not meant to be changed.”

Customer: “Oh, why is it there then?”

Support: “I dunno, let me ask an engineer… OK, he says why are we all here?… Maybe you should just change it back.”

The other issue is, whilst some parts of the library are incredibly configurable, the bit’s you really need access to are inaccessible. For example, in an enterprise application, it’s likely you might have a backup database connection. With this in mind, there doesn’t seem to be a way to enumerate all the database instances configured. I also can not find a way to create a database instance against a programatically generated connection string.

Some other minor problems I could live with but worth mentioning are:

  • Logging is slow compared to other libraries
  • You can’t store all your configuration in a single app.config [Edit: this is now possible with the extension library]
  • The documentation is too much “look at this cool design we did” and not enough “how to do…”
  • The fact that a patch had to be released fixing custom storage providers tells me that no one tested this feature – how much more wasn’t tested?

Hopefully I’m wrong on all counts and someone will provide me with answers to all my problems so I can do the right thing and continue using it. Maybe next week I’ll have better news to report.

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Saturday, March 05, 2005 10:01:15 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] Trackback
# Wednesday, February 02, 2005

Ward Cunningham’s recent contributions to Microsoft have appeared on the web in the form of a wiki called PatternShare. The content is excellent but what I find more interesting is that the person who invented the wiki concept is (a) using FlexWiki instead of his original creation and (b) doing some really novel things with the software itself.

Having never programmed in SmallTalk, I haven’t really got my head around WikiTalk so my FlexWiki development is limited to modifying existing examples. This new site has plenty of those.

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Wednesday, February 02, 2005 10:15:47 PM (GMT Standard Time, UTC+00:00)  #    Comments [2] Trackback
# Saturday, January 15, 2005

This one can be expanded to selling anyone on an idea:

The usual set of MSDN articles:

Some notable downloads:

Finally, a couple of excellent articles by Michele Leroux Bustamante (dasblonde)

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Saturday, January 15, 2005 10:48:09 AM (GMT Standard Time, UTC+00:00)  #    Comments [0] Trackback
# Saturday, December 18, 2004

My feed list is starting to get out of hand. It's so large that I've started adding feeds already subscribed to because I can't remember if they are new or not. Robert, I don't know how you keep up with all your feeds.

To help, I've knocked together a little tool to clean duplicates out of my OPML file. It's a .NET console application so just supply the relevant filename on the command line. It will backup the file before processing. Source is included but it's nothing special. Enjoy.

Now playing: - Ryan's Radio

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Saturday, December 18, 2004 2:15:46 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] Trackback
# Saturday, November 27, 2004
Here’s a quick guide to code reviews from the Mozilla project. It’s aimed at C++ but most of the principals are language independent.
by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Saturday, November 27, 2004 6:48:32 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] Trackback
# Saturday, November 13, 2004

Ian Griffiths posted an article on "How To Stop a Thread in .NET", but as Richard Blewett pointed out "...the thread has to be able to check the flag to know it has to bring itself down...".

Richard's solution is better but I prefer another for a number of reasons:

  • The code could be waiting for 2 seconds before the Sleep gets interrupted
  • We can get rid a a few lines of code
  • I think this solution is clearer

What both articles are talking about is a shutdown event. In which case why not use the timeout for a sleep? So modifying Richard's code we have:

static ManualResetEvent
    shutdownEvent = new ManualResetEvent(false);

static void Main(string[] args)
{
    Thread t = new Thread(new ThreadStart(Func));
    t.Start();

    Console.ReadLine();

    // set the event to get the thread to come down cleanly
    shutdownEvent.Set();

    // wait for it to terminate
    t.Join();
}

static void Func()
{
    // open some resource that requires clean up
    using(FileStream fs =
                File.OpenWrite(@"C:\foo.txt"))
    {
        // check the event
        while(!shutdownEvent.WaitOne(10000, true))
        {
            // use the resource
            fs.WriteByte(0);
        }
    }
}

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Saturday, November 13, 2004 2:03:02 PM (GMT Standard Time, UTC+00:00)  #    Comments [2] Trackback
# Sunday, November 07, 2004

The primary reason for writing this article is I've managed to make exactly the same mistake on two separate occasions. A third time would be careless...

For this particular recipe you need:

  • A .NET application that uses COM interop (any should do but I'm using SQLServer DSO)
  • A Visual Studio installer project

First add the output of your COM interop project to the installer project and, as if my magic, the COM DLL that your interop is using will be added to the installer. Next build your solution and install your new application. Then spend a couple of hours trying to work out why nothing works and you get strange error messages like "Could not find msmdso.rll" whenever the COM object is instantiated. This is especially difficult if your application happens to be running as a service and COM DLL displays the message in a message box (hint: listen for the unmistakable "ding" of the message box sound).

What has happened? Well when the COM DLL was automatically detected and added to the installer project it was flagged as "vsdrfCOMSelfReg" which causes the new copy of the DLL to registered at install time zapping the original COM registration. As for the message box, nothing you can do if it's DSO like mine unless you happen to work for Microsoft.

For some reason setting the flag back to "vsdrfDoNotRegister" still causes issues and the best approach is to set the "Exclude" property to true and completely remove the DLL from the installer.

One last tip. If you manage to do this with DSO then you can avoid reinstalling Analysis Server by executing the following:

cd "C:\Program Files\Common Files\Microsoft Shared\DSO"
for %i in (*.dll) do regsvr32 %i
by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Sunday, November 07, 2004 7:44:14 PM (GMT Standard Time, UTC+00:00)  #    Comments [2] Trackback
# Friday, October 29, 2004
Another great article from Scott. This time on Testing ASP.NET 2.0 and Visual Web Developer.
by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Friday, October 29, 2004 5:02:11 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback
# Sunday, October 24, 2004
I just wanted to link to this article by Scott Guthrie so the guys in the office could find it. It's an excellent article about driving up code quality by getting to a known point and staying there.
by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Sunday, October 24, 2004 9:09:43 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback
# Sunday, October 17, 2004

I'm just working on the membership part of the web site and as the user configuration is stored in a file I wanted to make sure it was going to be saved safely. Simple, just copy the file to a backup before saving. If anything goes wrong then restore the backup. The code is a little fiddly and I want to use if everywhere I save a file so I've created a little utility struct.

    public struct AutoBackup : IDisposable
    {
        private string file;
        private string backup;

        public AutoBackup(string file)
        {
            this.file = file;
            this.backup = file + ".bak";

            if (File.Exists(this.file))
            {
                File.Copy(this.file, this.backup);
            }
        }

        public void Dispose()
        {
            if (File.Exists(this.backup))
            {
                File.Copy(this.backup, this.file, true);
                File.Delete(this.backup);
            }
        }

        public void DeleteBackup()
        {
            if (File.Exists(this.backup))
                File.Delete(this.backup);
        }
    }

It's a struct because it should always be created on the stack. Initially I had some problems because I was trying to modify the fields after initialisation; something you can only do with reference objects. Usage is as follows:

    using (AutoBackup bak = new AutoBackup(membershipFile))
    using (FileStream fs = new FileStream(membershipFile,
            FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
    {
        serializer.Serialize(fs, membership);
        bak.DeleteBackup();
    }

The DeleteBackup() call is to stop the auto restore functionality from kicking in. If anything happens during the save that causes an exception to be thrown then the using block ensures the old file is restored.

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Sunday, October 17, 2004 9:59:29 PM (GMT Daylight Time, UTC+01:00)  #    Comments [2] Trackback

A couple of days ago Somasegar announced that C# would have Edit and Continue support in VS 2005. Wow, great news... But hold on, haven't they been saying all year that they didn't have time to do both refactoring and edit & continue? What changed and more importantly, how has that affected the final delivery date? You don't just add in a major feature and expect everything else to stay the same. So I guess one of the following has happened:

  • They found a bunch of devs and testers who have nothing better to do
  • Yukon has delayed some more and since VS2005 shares the same CLR version they now have so much slack in the schedule that they can add the feature
  • The new feature has delayed the product

I don't expect the first option is correct. I suspect the second has happened. Even if it's the third then we have a schedule slip somewhere and an even longer wait. Come on guys, I thought Microsoft's 21 Rules of Thumb was all about begin schedule driven and not feature driven? I'm under pressure to use alternative technologies so if the wait is too long then I'm afraid you may lose your chance.

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Sunday, October 17, 2004 10:38:44 AM (GMT Daylight Time, UTC+01:00)  #    Comments [1] Trackback
# Saturday, October 16, 2004

I was just thinking about the overall architecture for the Golf Web application and whether or not it would be better to try and use existing products instead of trying to roll my own. I could use dasBlog and nGallery like this site does to provide pictures and allow members to update what they are doing.

This is the classic "buy vs build" decision that sometimes gets overlooked in software development. The cost equation is simple: will the purchase cost of the bought component + integration costs be greater or less than the cost of developing said functionality + support costs. Putting numbers in the equation is a little more difficult. Remember the purchase cost may include additional licensing fees. At Exony we have a simple rule for commercial components - if the component can't be redistributed royalty free or under OEM license then we don't use it. Open Source can be useful must don't forget to check the license especially the part about derivative works where the wrong license can commit your entire product to the public domain.

I'm not keen on using the two products mentioned above because they are complete overkill for what I want. There is a third way though, to use parts of the code base. The architecture will be mine but using code from the other two; sort of like a code snippet library. I've checked the licenses and this is allowed as long as I include the original license and copyright notices.

What I couldn't find though was any sort of .NET web contact manager. Does anyone know of one?

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Saturday, October 16, 2004 6:27:52 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback
# Wednesday, October 13, 2004

As promised previously, I want to dig a little deeper into the requirements and discuss some solutions. This post is going to be about the security and membership. The relevant requirements are:

  1. There system will only allow access to members, i.e. no public access
  2. The system should be simple and that includes registration
  3. Registration and security should be self maintaining wherever possible
  4. Lost password handling must be automatic

There are standard patterns for login and registration and you really want the users to feel in familiar territory whilst starting out with your application in otherwise they are likely to give up and never return. Also I want new users to be up and running as soon as possible.

First I have some choices to make so lets start with login id. Personally I find it difficult to remember my user names, particularly if registered with lots of web sites. I tend to try and pick the same one but obviously if someone else is using it then I have to pick a different one or a variation. I think using an e-mail address as a login is much more memorable and the chances of a clash are near zero. We will need the e-mail address as part of the registration process anyway so using it as a login id removes the need for choosing an additional login name or providing additional registration pages dedicated to telling the user to pick another name because it already exists.

Next the password. This is usually a weak point in any security system and I believe the best approach is to make it easy and secure for users retrieve a forgotten password. This way you can urge them to pick a more complicated pass phrase without them worrying about forgetting it. I need to allow for long passwords so there should be at least 100 characters available. Whilst we are on the subject of passwords, I intend to only store a salted hash so retrieving a password will be impossible. Lost passwords mean that the user will have to recreate a new one. There are two ways I could do this: either by generating a new password and e-mailing the result to the user or sending a special "one time" link instead which, when clicked on, allows the user to set a new password. As e-mail will travel unencrypted I prefer the second approach because the user is forced to select a new password and the link will only work once.

Finally, the registration process. This one is a little more complicated because I know Laura already has a list of contact details she wishes upload to the site. This means that contacts may already exist before the relevant user registers. I'm not sure if Laura intends the users to edit any contact or only their own details (I must remember to ask). If it's the latter then I'll need some mechanism for tying up the user to the contact. I could get the user to type in their address at registration and match that to an existing contact but there too much room for error when you consider things like "street" can be written as "st." etc. What I shall probably do is some sort of fuzzy match based on the post code and any other digits in the address. More on that at a later date. One benefit of matching the user to an existing contact is I can automatically validate a registration request saving Laura from a manual step. Any non-matches will have to manually verified unless I can think of some cunning way around the problem.

Thats all for tonight. As it's my birthday I'm going for dinner with friends tomorrow so the next installment will be at the weekend.

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Wednesday, October 13, 2004 9:54:11 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback
# Tuesday, October 12, 2004

My step mother asked for a favour this weekend. She has a rather large Word document of unsorted contact details and pictures that she wants to publish on the web. She wants me to see if I can provide a solution. I should start by saying this is a classic request of a programmer similar to "will you help fix my computer" and "I can't read my e-mail". I'm happy to do this, particularly as it's a fun little project, but it can turn into a bit of a commitment.

So what is this application supposed to do? Lets review some of the requirements from Laura:

  • The application will support a membership of a virtual golf club; they meet up for social reasons and to play different courses in the US and UK
  • Manage contact details for golf club members
  • Each contact has name, address, phone, e-mail and a picture
  • Members should be able to update their own details
  • Members can search for other member's details
  • The system will only allow access to members, i.e. no public access
  • The members can add descriptions of what they are up to

After thinking about this for a while I can see that there are some additional unwritten requirements. It's usual for the customer to not fully understand what they want and as an analyst you have to use your experience and fill in the gaps. You do need to go back to the customer and check your assumptions are correct though. So what are mine?

  • Simplicity - the users of this application are in their 40's, 50's and 60's so I'm going to make a sweeping generalisation and say they aren't too comfortable around computers.
  • Manageability - Laura is a busy person with better things to do than continually login and manage the system
  • Registration - to ease the management burden on Laura, this should be as automated as possible
  • Lost passwords - this is not an every day application so the large gaps between logins will increase the chance that the members have forgotten their passwords. It also needs to be automated so Laura doesn't have to do anything.
  • Meet-ups. This was not in the original list from Laura but it's the primary reason the club exists. Would it be worth placing on the product backlog?
  • Notifications - do the members want to be notified if anything has been updated? This will save them from the burden of logging in frequently.
  • Logging - this one is for me because if anything goes wrong then I'm the one getting the call to fix it
  • Hosting - I'll need to find somewhere appropriate to host the application. Luckily we checked and a suitable domain name is free.
  • Data Storage - I don't have experience of using databases on web hosts, though I know it's possible, so I want to try and use a file based data storage mechanism

Next time I'll discuss some of the requirements in more detail with respect to some possible solutions.

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Tuesday, October 12, 2004 8:25:16 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback
# Thursday, September 23, 2004

So you spend the odd evening and weekend playing with the brand new technologies emerging from Microsoft. Whether it's Yukon, Whidbey or Longhorn, there is plenty to mess around with. The more you play with these tools, the more you can dream of new ways to deliver exciting products in next to no time. Life is rosy.

However, we all need to pay the bills and that means going to work. Work is not about dreams, it's about delivering real solutions to customers now. Here is where the misery starts. You can't actually use these tech previews and betas for production code so you have to do things the old way. The old way is no fun. It's depressing and we are still at least a year away from a more pleasant life. It's not that the current tool set is bad, in fact it's great. Compared to the new versions, though, the difference is immense.

Personally, I think it's worse as I can't see any of our customers (apart from one very progressive one) upgrading to Yukon until it's been on the shelves for at least a year. In fact Cisco ICM is a product we depend on and their recent release has only just caught up with SQL Server 2000. Understandably there has to be a business benefit for them to upgrade. Maybe there is but at the moment all I see is developer benefit.

I talk primarily about Whidbey and Yukon as I'm not even going to look at Longhorn until it's a bit more tangible. Blog land is full of posts wondering if it's worth using WinForms for development. In fact Microsoft has recently been on the offensive trying to persuade customers that WinForms is not dead.

On a final note, I do actually like what Microsoft is doing with tech previews. It helps me align my architecture and development plans with theirs. It just makes going to work a bit of a drag in the meantime.

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Thursday, September 23, 2004 10:48:55 PM (GMT Daylight Time, UTC+01:00)  #    Comments [1] Trackback
# Monday, September 20, 2004

I have to admit I'm one of the people that Rob Caron was helping out this weekend. With living in the UK I find it second nature to set the system locale to 'English (United Kingdom)' whenever I do an installation. On this occasion it turns out to be fatal when installing the Team Foundation Server. The main effect of which is that the installer will fail to create the correct ADAM structures.

After reinstalling the application server I was able to connect to the Team Foundation Server and create Portfolio Projects; but during creation it failed to create the corresponding Sharepoint site. After checking that I could access the Sharepoint Central Site (administration page) I remembered I hadn't changed the locale on the client computer. A few clicks later and everything is now working. I just need to work out how to delete all the failed Portfolio Projects from the system.

I haven't spent too much time looking at it yet as the 8 hour time difference to Redmond means support from Rob came late in the evenings. Initial feelings are that it's going to be a great product. The thing the really impressed me is not the product (yet), but the customer service I received from Rob. He spent a large amount of time this weekend trying to solve my problems when he didn't need to. All he wants in return is feedback on the product. It makes you feel kind of special. Certainly it makes me want to use the product. Thanks Rob. 

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Monday, September 20, 2004 10:11:39 PM (GMT Daylight Time, UTC+01:00)  #    Comments [2] Trackback
# Sunday, September 12, 2004

I have my guest systems configured to use their own network because I don't want my ISP moaning about DHCP and domains appearing on the subnet. The lack of "Shared Folders" in Virtual Server makes life difficult as it also won't mount ISO's larger than 2GB; you have to actually burn the image onto a DVD to use it in a guest operating system. The next challenge comes from Sharepoint Team Services and Active Directory Application Mode - these setup files are executables not CD images so can't be mounted. The solution, use mkisofs to create an image with the correct files on.

Finally, Visual Studio 2005. The handy hint here is not having "undo disks" enabled or you will grow old before it completes. If you are going to install the supplied MSDN then block out a full day anyway...

OK, everything installed... Fire up Visual Studio and connect to the Team Foundation Server... Yep, it connects. Try and create a portfolio project and... Bam! Access Denied... F#!%$%*k

I've just given a whole Sunday to this thing... Does anyone know what the problem is? I've tried adding the user to Global Administrators group as described in the docs but GssUtil reports that the identity "adm:" cannot be resolved.

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Sunday, September 12, 2004 6:52:29 PM (GMT Daylight Time, UTC+01:00)  #    Comments [4] Trackback
# Friday, September 03, 2004

One of the nice things about System.String is that two variables having the same contents will point to the same object once they have been interned. So you have the following:

string s1 = "abcdef";
string s2 = "abcdef";

object o1 = string.Intern(s1);
object o2 = string.Intern(s2);

Debug.Assert(o1 == o2);

This can be put to good use when you want to use caching... If the non-cache lookup is expensive, say a database call, you want to ensure that the lookup operation will only happen once in the presence of multiple threads. The lock(cache) keyword is ideal but not very granular. An alternative is the lock the cache key:

public string GetFromCacheOrLookup(string key)
{
    lock (string.Intern(key))
    {
        string result = (string)cache[key];

        if (result == null)
        {
            result = LookupFromDatabase(key);
            cache[key] = result;
        }

        return result;
    }
}

This method allows multiple threads to perform the expensive lookup as long as the key is different; if not then they wait for the initial lookup to complete before continuing.

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Friday, September 03, 2004 1:07:43 PM (GMT Daylight Time, UTC+01:00)  #    Comments [3] Trackback
# Tuesday, August 31, 2004
by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Tuesday, August 31, 2004 11:25:44 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback
# Sunday, August 15, 2004

I've just noticed a very nice side affect from having the refactoring functionality in VS2005. When you rename something using the property window, it automatically updates all the references. So you know what has just happened this appears in the refactor window:

Rename
d:\work\dataentry\form1.designer.cs(3,16): updated definition
d:\work\dataentry\form1.cs(14,16): updated definition
d:\work\dataentry\form1.cs(16,10): updated reference
D:\Work\DataEntry\Program.cs(21,24): updated reference

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Sunday, August 15, 2004 12:23:16 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback
# Friday, July 16, 2004

When you install dasBlog in the root of a web server as I have, it's web.config is inherited by all lower level applications. This is a problem for nGalley as the dasBlog config has <httpModules> loaded. You can unload them by adding the following to the nGallery web.config:

<httpModules>
  <remove name="ControlImageModule" />
  <remove name="UrlMapperModule" />
  <remove name="CompressionModule" />
</httpModules>

This doesn't quite solve the problem though as the nGallery application still needs to be able to load the dasBlog assemblies in order to remove the <httpModules> so add the dasBlog assemblies to the nGallery bin folder.

I'm not too sure why you still need the assemblies in the nGallery bin directory - maybe someone can enlighten me.

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Friday, July 16, 2004 10:15:00 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback
# Tuesday, July 06, 2004

One of the main talking points at Tech Ed was whether to use remoting or enterprise services to talk between service tiers. For the benefit of the guys at work I thought I'd try and collate some of the information thats available and draw some guidelines. I won't cover ASMX/WSE as I believe there is no argument there - for talking between services use ASMX.

Firstly, for an overview of the options for hosting objects and communicating with them, you can't beat Don Box's bullets:

Don however doesn't mention remoting as he is really against it. Rock Lhotka provides a view that includes remoting:

These two articles from Richard Turner (a program manager working on "Indigo") give you the inside view.

Finally, another good roundup is by Aaron Skonnard reviewing Richard Turner's Tech-Ed session:

I think the general guidance from all these articles is that remoting is OK given the following rules:

  1. Only use it between tiers on the same machine (Otherwise use DCOM/ES instead)
  2. Don't use any of the custom stuff like formatters and sinks
  3. Don't use it at the service boundary (Use ASMX instead)
  4. You MUST use remoting to communicate between app domains in the same process
  5. You may have to do some rework when Indigo arrives
by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Tuesday, July 06, 2004 12:15:23 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback
# Tuesday, June 29, 2004
Announcing Visual Studio Express Edition - a cut down version of all the Visual Studio tools that the're pretty much going to give away. Also, download the Visual Studio 2005 Beta from http://msdn.microsoft.com/vs2005.
by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Tuesday, June 29, 2004 3:29:45 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback