harriyott.com

29 March 2007

Inspirational Entrepreneurial Geekiness

Having been to the excellent first £5 app (i.e. writing an app in evenings and weekends) evening yesterday, I spent a couple of hours tonight on my effort. I fixed a bug reported by my user (yes, singular, and he's also my partner in this venture), and added a couple of new features.

Mine's a little different in that it has to be a Windows client application, rather than web, but I haven't had to spend a penny yet (no, that's not a euphemism), as I don't need to host it anywhere. Although a few people know what it is, I can't really write about it yet as the deployment environment is a little sensitive. Once we've fixed the strategy, I'll be able to say more.

And Ian, if I get ten customers, I'll volunteer to speak at a future £5 app event.

[Tags: ]

28 March 2007

Previous EurotaxGlass's colleagues blogging

Kelly Waters, who I used to work for, has started blogging about agile development. Kelly was very supportive of my blogging when I worked for him, even though the higher-ups at EurotaxGlass's were "concerned" by it.

Ben Sales, who I sat opposite at EurotaxGlass's has also started blogging recently. He's got himself a plum job doing extremely agile Ruby on Rails programming, and he's blogging about learning it all from a .NET developer's perspective.

[Tags: ]

28 March 2007

Getting the mouse wheel working in VB6

I occasionally have to use VB6, and I'm always frustrated by the mouse wheel not working. One of my colleagues pointed me to a download to get the thing in action.

[Tags: ]

23 March 2007

Adding dynamic nodes to ASP.NET site maps at runtime by deriving from StaticSiteMapProvider

Adding a static sitemap to an ASP.NET website is straightforward. Creating a dynamic sitemap is harder, but there are several articles that Google finds describing how. Adding dynamic items to an existing sitemap seems harder still: you can't add items by deriving from XmlSiteMapProvider, as the list of SiteMapNodes is read only.

The method for adding items to a sitemap has a few steps:
  1. Create your sitemap file in the usual way.
  2. Derive a class from StaticSiteMapProvider.
  3. Add your sitemap to the Web.Config file.
  4. Check that this works by adding a tree view connected to a sitemap data source.
  5. Implement the overridden base-class methods.
  6. Read the sitemap file into an XmlDocument.
  7. Dynamically add new elements to the XmlDocument.
  8. Recurse through the XmlDocument creating a tree of SiteMapNodes.


In step 1, your sitemap file may look something like this:

<?xml version="1.0" encoding="utf-8" ?>

<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >

    <siteMapNode url="~/default.aspx" title="Home"  description="Home page">

        <siteMapNode url="~/contact.aspx" title="Contact"  description="Contact us" />

        <siteMapNode url="~/products.aspx" title="Products"  description="Our products" />

    </siteMapNode>

</siteMap>



For step 2, just create the class at the moment:

namespace Harriyott.Web

{

    public class DynamicSiteMapProvider : StaticSiteMapProvider

...

You'll be prompted (by a tiny rectangle) to implement the abstract class, which you should do, and replace the exceptions with return null; for now.

For step 3, add the site map provider in the usual way, but change the type to your new class name, including the namespace:

<system.web>

    <siteMap defaultProvider="main">

        <providers>

            <add siteMapFile="Web.sitemap"  name="main" type="Harriyott.Web.DynamicSiteMapProvider"/>

        </providers>

    </siteMap>



To see what we have so far, step 4 is to add a new .aspx page with a tree view displaying the site map.

<asp:TreeView ID="treeSiteMap" runat="server" DataSourceID="smdsHarriyott" />

<asp:SiteMapDataSource ID="smdsHarriyott" runat="server" />



Although this should run ok, no items are displayed yet. This is because the StaticSiteMapProvider class doesn't actually process the sitemap XML, because we're returning null. To see the static site map items, switch the type in the Web.Config back to the default:

type="System.Web.XmlSiteMapProvider"



OK, so step 5 is to implement the overridden methods and properties properly. Or properlies property.

private String _siteMapFileName;

private SiteMapNode _rootNode = null;

 

public override SiteMapNode RootNode

{

    get { return BuildSiteMap(); }

}

 

public override void Initialize(string name, NameValueCollection attributes)

{

    base.Initialize(name, attributes);

    _siteMapFileName = attributes["siteMapFile"];

}

 

protected override SiteMapNode GetRootNodeCore()

{

    return RootNode;

}

 

protected override void Clear()

{

    lock (this)

    {

        _rootNode = null;

        base.Clear();

    }

}



The first bit is quite straightforward. There's a root node to add sitemap nodes to, and we're saving the filename of the sitemap file. The interesting bit is to create the nodes. This is done in BuildSiteMap():

private const String SiteMapNodeName = "siteMapNode";

 

public override SiteMapNode BuildSiteMap()

{

    lock (this)

    {

        if (null == _rootNode)

        {

            Clear();

            // Load the sitemap's xml from the file.

            XmlDocument siteMapXml = LoadSiteMapXml();

            // Create the first site map item from the top node in the xml.

            XmlElement rootElement =

                (XmlElement)siteMapXml.GetElementsByTagName(

                SiteMapNodeName)[0];

            // This is the key method - add the dynamic nodes to the xml

            AddDynamicNodes(rootElement);

            // Now build up the site map structure from the xml

            GenerateSiteMapNodes(rootElement);

        }

    }

    return _rootNode;

}



Four main things going on here. (Four things. Please don't be confused by me saying things like "And fourthly, step 8", as I'm still trying to keep track of the list at the beginning.) Firstly, in step 6, the XML file is loaded:

private XmlDocument LoadSiteMapXml()

{

    XmlDocument siteMapXml = new XmlDocument();

    siteMapXml.Load(AppDomain.CurrentDomain.BaseDirectory + _siteMapFileName);

    return siteMapXml;

}



Secondly, we're selecting the top siteMapNode from the loaded XML. Thirdly, and this is the important step 7, we're going to add our dynamic nodes:

private void AddDynamicNodes(XmlElement rootElement)

{

    // Add some football teams

    XmlElement teams = AddDynamicChildElement(rootElement, "", "Football Teams", "List of football teams created dynamically");

    AddDynamicChildElement(teams, "~/teams.aspx?name=Watford", "Watford", "Watford's team details");

    AddDynamicChildElement(teams, "~/teams.aspx?name=Reading", "Reading", "Reading's team details");

    AddDynamicChildElement(teams, "~/teams.aspx?name=Liverpool", "Liverpool", "Liverpool's team details");

 

    XmlElement sheffield = AddDynamicChildElement(teams, "", "Sheffield", "There is more than one team in Sheffield");

    AddDynamicChildElement(sheffield, "~/teams.aspx?name=SheffieldUnited", "Sheffield United", "Sheffield United's team details");

    AddDynamicChildElement(sheffield, "~/teams.aspx?name=SheffieldWednesday", "Sheffield Wednesday", "Sheffield Wednesday's team details");

 

    XmlElement manchester = AddDynamicChildElement(teams, "", "Manchester", "There is more than one team in Manchester");

    AddDynamicChildElement(manchester, "~/teams.aspx?name=ManchesterUnited", "Manchester United", "Manchester United's team details");

    AddDynamicChildElement(manchester, "~/teams.aspx?name=ManchesterCity", "Manchester City", "Manchester City's team details");

}



I'm just doing this in memory to keep the example short, but you could generate stuff from your database. The AddDynamicChildElement returns a new child that's been added to the current node:

private static XmlElement AddDynamicChildElement(XmlElement parentElement, String url, String title, String description)

{

    // Create new element from the parameters

    XmlElement childElement = parentElement.OwnerDocument.CreateElement(SiteMapNodeName);

    childElement.SetAttribute("url", url);

    childElement.SetAttribute("title", title);

    childElement.SetAttribute("description", description);

 

    // Add it to the parent

    parentElement.AppendChild(childElement);

    return childElement;

}



And fourthly, step 8 is to generate the site map nodes in, er, GenerateSiteMapNodes():

private void GenerateSiteMapNodes(XmlElement rootElement)

{

    _rootNode = GetSiteMapNodeFromElement(rootElement);

    AddNode(_rootNode);

    CreateChildNodes(rootElement, _rootNode);

}

 

private void CreateChildNodes(XmlElement parentElement, SiteMapNode parentNode)

{

    foreach (XmlNode xmlElement in parentElement.ChildNodes)

    {

        if (xmlElement.Name == SiteMapNodeName)

        {

            SiteMapNode childNode = GetSiteMapNodeFromElement((XmlElement)xmlElement);

            AddNode(childNode, parentNode);

            CreateChildNodes((XmlElement)xmlElement, childNode);

        }

    }

}



What's going on here is that we're creating a root sitemap node from the root element in the XML. Then we're recursively finding the XML element's children and adding coresponding sitemap nodes to match the hierarchy. Here's the method that creates a sitemap node from the XML element:

private SiteMapNode GetSiteMapNodeFromElement(XmlElement rootElement)

{

    SiteMapNode newSiteMapNode;

    String url = rootElement.GetAttribute("url");

    String title = rootElement.GetAttribute("title");

    String description = rootElement.GetAttribute("description");

 

    // The key needs to be unique, so hash the url and title.

    newSiteMapNode = new SiteMapNode(this,

        (url + title).GetHashCode().ToString(), url, title, description);

 

    return newSiteMapNode;

}



So that's it. We now have a static site map with items dynamically added to it. Just to prove it, here's what mine looks like on an Angel Delight coloured background:

Site map screen shot

To save you piecing this all together in a new class, you can download the full source file.

[Tags: ]

21 March 2007

Bristol .NET Developer Network

Guy Smith-Ferrier has just let me know about the .NET Developer Network, a free .NET user group based in Bristol. This involves monthly meetings, the first of which is on 23rd April, about LINQ, and presented by Mike Taulty. I've seen Mike present before, and he's worth watching.

[Tags: ]

20 March 2007

More Football Club RSS Feeds

Having successfully created an RSS feed for the syndicationally-challenged Watford FC, I have (with the prompting of Mike), made a start on the rest of the Premiership clubs. From the ones I've looked at, most are using the same CMS, a couple of others are using a different CMS, and others (Charlton Athletic, Everton, Fulham and Tottenham Hotspur) already have their own RSS feed.

I've put a page up listing the ones I've done so far, which include
  • Aston Villa
  • Blackburn Rovers
  • Bolton Wanderers
  • Manchester City
  • Middlesbrough
  • Reading
  • Sheffield United
  • Watford
  • West Ham United
  • Wigan Athletic

I'll look at the rest in the near future. Manchester United and Arsenal's look tricky, so I'll leave them until last. If there are any non-Premiership teams that you'd like RSScraped, leave a comment and I'll add it to my list.

[Tags: ]

17 March 2007

Watford FC News RSS

Being an (emerging) Watford FC fan, I've been finding it a little frustrating that their official site doesn't have an RSS feed.

So I wrote one. I've stuck it through feedburner.

[Tags: ]

12 March 2007

First day at first contract

And it was a good one. The people were all nice (that I spoke to), the coding standards were sensible, the code was laid out nicely and the project structure was good. The people I spoke to all seem competent and (just as importantly) helpful. They use FogBugz rather than TestTrackPro. The meeting was short and focused. I signed off three bugs already. There was another contractor started today too, who also had a tablet PC with him (I like him already!).

OK, they were the good things, but there were a couple of not-so-good things. I found some HTML markup (<b> tags) in the business logic layer, and a div's background image that was a complete rounded box - i.e. fixed size, not a separate top and bottom, so increasing the browser's text size pushed the text outside the box. I'd be worried about myself if I couldn't find something though. Oh, and SourceSafe.

It's a little bit annoying being a new boy and having to ask all the basic questions about where things are, what to put in check-in comments, bug reports etc, but I'll soon be over that.

I feel at home already, but then I do whenever I move house or go on holiday. I'm going to miss some of my old colleagues, but I'll see them at the reunion soon.

9 March 2007

Last day at EurotaxGlass's

Simon Harriyott is leaving the building. For the last time.

I'm happy to be starting a new contract on Monday, but sad to leave some of the lovely people I've worked with for the last couple of years, and disappointed that I didn't get to finish the major project I've been working on since I started here. Good luck to the outsourcing company taking over the code - around 12 to 15 man-years of work!

6 March 2007

RSS component for .NET

I've started work on the website for my new company, Pleasant Development. I'm not going to put a new blog on there; instead, I'll fetch the latest entries from RSS and just display the titles. I've found a great component to do this on Dmitryr's blog. Five lines of code, and there it is. [n.b. the site isn't live yet, so there it isn't at the mo.]

1 March 2007

Unexpected conversation

Watford Geek Venn Diagram

A = Watford fan
B = Geek
C = 2



[Tags: ]

1 March 2007

Sussex Geek Dinner with Geoff Adams

Last night's was the ninth geek dinner I've hosted now, and the busiest yet, with 30 people turning up. I reckon I could squeeze two more in, so I've updated the upcoming page for the next one (which already has 30 booked in).

I'm having to accept that I just can't talk to everyone now. There was about two hours after the talk finished, which would mean just 4 minutes with each person. I plumped for quality over quantity, and had a really good chat with Jez Nicholson, who I met at right at the end of the last geek dinner.

Jez and I are both into the same fantasy football website, which is great from a data point of view, but would definitely benefit from being a whole lot more "web 2.0". I would really like RSS feeds of players' injuries or suspensions so I would know to make a substitution.

I met Adam Khan, who's recently moved to Brighton from Italy, and Andy White, who volunteered to speak at a future dinner. I've now got speakers for the next three geek dinners, which is great.