Tuesday, September 25, 2007

A simple 'Check for updates'

My brother asks when I'll post something interesting on here, but it hasn't happened yet so I doubt it will anytime soon... Anyway it seems the most boring posts are the most popular so I'll keep on posting crap.

Back to the point of this post. Lots of applications these days will check for an update when they start or when you press a 'Check for updates' button or menu item. Some really annoying applications have some little helper process that runs continuously and checks on a regular basis then throws up a big dialog telling you that there's an update (that's you Apple).

Not wanting to be left out, I thought I'd do the same. But being incredibly lazy, I couldn't be bothered to implement it completely. So this little bit of code will read a text file stored on the web server and tell the user that an update is available. It won't do anything fancy like download it for them or install it but I might add that at some point. Usage is simple, set the Url property to tell the component where the text file is stored, then call CheckLatestVersion() to show a message saying there is a new version available.

 

using System;
using System.ComponentModel;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Reflection;
using System.Windows.Forms;

namespace FreeFlowAdministrator
{
    /// <summary>
    /// Component to check for updates for an application.
    /// </summary>
    public class UpdateChecker : System.ComponentModel.Component
    {
    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.Container components = null;

    public UpdateChecker(System.ComponentModel.IContainer container)
    {
      ///
      /// Required for Windows.Forms Class Composition Designer support
      ///
      container.Add(this);
      InitializeComponent();
    }

    public UpdateChecker()
    {
      ///
      /// Required for Windows.Forms Class Composition Designer support
      ///
      InitializeComponent();
    }

    /// <summary> 
    /// Clean up any resources being used.
    /// </summary>
    protected override void Dispose( bool disposing )
    {
      if( disposing )
      {
        if(components != null)
        {
          components.Dispose();
        }
      }
      base.Dispose( disposing );
    }


    #region Component Designer generated code
    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
      components = new System.ComponentModel.Container();
    }
    #endregion

    private string url;
    public string Url
    {
      get
      {
        return url;
      }
      set
      {
        url = value;
      }
    }

    public string GetLatestVersion()
    {
      HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(url);

      // Sends the HttpWebRequest and waits for the response.
      HttpWebResponse myHttpWebResponse = myReq.GetResponse() as HttpWebResponse;
      try
      {
        Stream response = myHttpWebResponse.GetResponseStream();
        StreamReader readStream = new StreamReader(response, System.Text.Encoding.GetEncoding("utf-8"));
        return readStream.ReadToEnd();
      }
      finally
      {
        // Releases the resources of the response.
        myHttpWebResponse.Close();
      }
    }

    public void CheckLatestVersion()
    {
      string latestVersion = GetLatestVersion();
      string currentVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
      if (latestVersion == currentVersion)
        MessageBox.Show("You are using the latest version");
      else
        MessageBox.Show(string.Format("The latest available version is {0}\nYou are using version {1}", latestVersion, currentVersion));
    }
  }
}

Thursday, September 20, 2007

Getting directions using Google Maps

I'm not sure when this feature was added but Google Maps now lets you drag your route around, if you want to go via a particular place. I'm not sure how useful this will be for me, but it's certainly cool to play with. Saying that I have asked for a web app to create Google Maps routes previously, and this is certainly heading in the right direction. It's possible to embed the map in a web page via an IFrame pretty easily, but I can't add markers and images, so not quite there yet. I was going to embed the route of my bike ride today but of course it doesn't understand about going off road or, erm, going through pedestrianised areas so I didn't have any luck with that.

Another great new feature is the information about bus departures, although weirdly I'm only seeing these in my local area, Kingston. It seems to be getting its information from Transport Direct, a website I've never seen before, but that looks like it goes some way to fulfilling my request for a site with complete knowledge of all the different transport options. It seems to be missing some pricing information but it knows about trains, buses and cars. Depressingly enough, cars are always cheaper than the more environmentally friendly option. Saying that, it claims a 200 mile journey by car is more environmentally friendly than the train, if the car has 4 occupants. But the train will be running anyway and using just the same amount of CO2, so what to do?

Some time ago I complained that Google Maps' directions to Heathrow from my house were completely ludicrous. Well it looks like they've fixed that as well, I'm sure they must have read my post...

Wednesday, September 19, 2007

Buy a people carrier

PeopleCarrier It got us to Spain and back in one piece with not a hiccup, but now it's time to pass our trusty vehicle on to someone else. If you're interested then check it out. All reasonable offers will be considered.

Monday, September 17, 2007

More reliable wireless

When I set up our wireless router, I initially set it up as an unsecured network and restricted access to certain MAC addresses. This worked fine but when we had visitors who wanted to use our wireless connection, it was a bit of a pain to allow access to their laptop. So I changed the router's configuration so it used WPA security and it all seemed to be working fine.

But then a couple of things happened which I didn't realise were related to this seemingly simple change I'd made. First, the wireless connection would stop working every few hours. This affected any computer connected to the network and would typically last a few minutes and then everything would be fine again. This was particularly annoying when I was connected to somebody's VPN and would have to re-establish a connection. The second problem was my Vista PC started to lock up completely. This was less frequent, about once a day.

I put the first problem down to the number of wireless networks in close proximity to our house. I guessed that they were just interfering with each other and causing the connection to drop every so often. Either that or our router was just getting on a bit. Then the other day I thought I'd give Vista's wireless diagnostics a spin and it told me the wireless security key was incorrect. What the...? This kicked my befuddled brain into action and realised these connection problems had started at the same time as the switch to WPA. So I switched back to an insecure network and lo and behold, the wireless connection is working a treat. Not only that but I haven't (fingers crossed) had a Vista freeze since the switch back.

So, if you're having wireless troubles, consider switching to an insecure network. I guess it may well be specific to my router but it may just work. Yeh, hackers can probably read my email, but frankly I hope they have more interesting things to do with their time.

Sunday, September 16, 2007

Are we in a fast moving industry?

It's virtually taken for granted that we work in a fast moving industry and the facts would appear to back up this theory. Just look at the new programming tools coming out of Microsoft (I'm just going to talk about them since I don't really even try and keep up with technology coming out of other companies). In no particular order, some of them are: WPF, WCF, WF, Silverlight, Linq, CardSpace, Virtual Earth, ASP.NET AJAX, Vista...

But hang on a second, who is using this stuff and how much of it will be relevant in five years time? Myself, the only new technology I'm looking at is Windows Workflow, since it may well be useful in my job. The rest may become relevant at some point and if and when it does I'll start looking at it then. And I'm a  geek who likes to fiddle around with new technology. What about the normal people out there who aren't obsessed with software?

Well, it doesn't look so good there either. Take IE7, which has been out for almost a year. Usage stats on the sites I maintain suggest just over 30% of IE users have upgraded to version 7. This is a free bit of software, but still almost 70% of users haven't upgraded. Admittedly some of these will be corporate users who have probably decided not to roll it out yet, but why not? Probably because IE6 is good enough, thank you very much.

And what about Vista? Well I'm seeing just short of 5% of Windows users are on Vista, which makes it somewhat more popular than Server 2003 (and who browses the internet from Server 2003 anyway?) but still less popular than Windows 2000 which, as the name suggests, is about 7 years old.

Here's something else to illustrate my point. I was up the loft the other day and found the notes for a C++ course I went on about 10 years ago. Flicking through them I realised I should probably keep hold of them, since they were still relevant today. Not only were they useful to C++ programming, but also to C#. The basic ideas behind object-oriented programming still apply. And you know what, if I still had the notes for my university C++ course from 17 years ago, they would probably still be relevant as well*

So yes, it's certainly possible to think we work in a fast-moving industry and it's certainly possible to work as if everything is in a constant state of flux. But it's also possible to move into a slower lane and just watch the shenanigans going on from a distance, wait for the dust to settle and learn the stuff that actually becomes important.

 

*You may be wondering why I needed to go on a C++ course when I was working if I'd already been taught it at university. Well I never paid much attention at uni, I was more interested in getting drunk and trying to pull young ladies...

Tuesday, September 11, 2007

Handling 404 errors in PHP

If you're running a PHP site on your own server, you can find out what 404 errors have occurred by viewing the log files. If, like me, you're running your PHP site on a cheap and cheerful host, you're probably not going to have access to the log files. But you can probably still do something to find out about them.

The first thing to do is ensure your users see a useful error message, rather than the default provided by your host, which will probably be some page advertising their services. This can be achieved via the .htaccess file, if your site is running on Apache. IIS has similar features, available through its admin tool (although I can't believe there are many people using PHP on IIS). Add something like the following to the .htaccess file to tell Apache to show your custom error page.

  ErrorDocument 404 /error.php

The next thing to do is to make sure you get notified if somebody ends up on a non-existent page on your site, so just add the following code to error.php somewhere.

  
  $message = "URL: " . $_SERVER["REQUEST_URI"] . "\n" . "Referrer: " . $_SERVER["HTTP_REFERER"] . 
    "\n" . "Browser: " . $_SERVER["HTTP_USER_AGENT"];
  mail("you@wherever.com", "404 error", $message);

And that's that. Well except the referrer doesn't seem to work for me... But it's already been useful, I've found one spurious bit of CSS trying to load an non-existent image, although I've also had quite a few false positives.

Friday, September 07, 2007

Yet more tick mark fun

I've written about this three times now. Read my previous posts here

But it turns out it's not as simple as the browser somebody is using. The other day I noticed that my tick marks weren't displaying on a computer that had IE7 installed. After more fiddling around I realised the fonts installed on that particular PC must be different to the ones installed on other PCs I'd tested and IE7 was unable to find the tick mark. I'm not sure whether IE7 only uses the current font or if it tries other fonts in an attempt to find the correct symbol but in any case it just displayed a square block.

Because of this I'm thinking perhaps the only 100% reliable solution is to either use an image or to display a checkbox in all situations, not just for IE6. In a desperate attempt to avoid either of those solutions, I've started using the 'Arial Unicode MS' font for my document. I guess this is fairly unlikely to work on Macs and Linux boxes, but they aren't particularly high on my list of required supported environments and they will fall back to more conventional fonts anyway, which hopefully work for these computers.

Update: Even the ‘Arial Unicode MS’ font won’t always work, even on Windows. This font is not installed by default on Windows systems, but it does come with Office, which I guess most Windows users will have installed.

Sunday, September 02, 2007

Road trip map

After some fiddling around with Google Maps I've managed to come up with a little map of our journey through France and Spain. It would be way cool if somebody came up with a web app that could be used by normal people to do this kind of thing...

Monday, August 27, 2007

Increment by increment

Popular music lyrics don't often use the word "increment" so I was pleased to hear British Sea Power use it on their first album. In fact they use quite a few unusual words and phrases. But "increment" has stuck in my head because it's such an important word to me.

Take programming for instance. Joel Spolsky calls development "The Game of Inches", but personally I prefer to think of it as a game of millimetres. It's probably partly due to my metric background but also inches suggests you might spot you've made progress after a day, whereas often I'll only recognise some progress has been made on a development project after weeks or months. Perhaps I'm just a slower programmer...

The fact is you can't make a lot of headway in a day. Which is probably why agile development has become popular. I'm not sure about parts of agile development but the idea of taking baby steps to get to where you want to be seems like a pretty damn good idea and I've done it myself for years.

Big designs have lots of problems. It's impossible to keep the details of a massive project in your head. Then things change part way through, or the design wasn't as well thought out as you initially thought. Then your boss tells you we need to release something next week... So it goes on.

The Random Pub Finder started as a craply designed site with hardly any content. Six years later, after hundreds of tiny steps, I'm now quite proud of it.

The FreeFlow Administrator started as a simple project to solve a particular problem I had. A year or so later and it's a fully fledged application that beats the Metastorm provided tools in pretty much every respect.

The commonality between these two projects is that both started small and have had working functionality from the start and at all the intermediate steps. Perhaps it's agile but I prefer to think of it as incremental. Agile brings to mind scrum meetings and pair programming. Perhaps they help but they aren't the important bit as far as I'm concerned.

Which makes me wonder why you'd want to develop stuff any other way. Most projects I've seen with huge design documents actually fall into an incremental development lifecycle as they progress anyway, so why not start out that way?

Thursday, August 23, 2007

What I learnt on the road trip

Take as few tents as possible - Campsites in Europe generally charge per person, per vehicle and per tent. Since you can't do much about the first two, the only way to save money is to bring a single tent that's big enough for everybody to fit into. The downside of this is the possibility that your big tent won't fit in the plot, but most sites seem to provide a pretty big space for you.

Take some kind of mattress - I've always slept directly on the ground in the past without problem, but the campsites in Europe can have much harder ground than the sites in blighty, with little or no grass, leading to some not very restful nights.

Spanish people stay up very late and have exceedingly loud TVs - I guess I already knew they stay up late, but hadn't considered the potential problems when staying in a camp site. Most of Spain takes the whole of August off and some of them head off to camp for a month, along with their tellies. They are then involved in an arms war in an attempt to drown out the sound of other campers' TVs, leading to yet more lack of sleep. In the site we were in, we also right next to the train line into Barcelona... Loudest... campsite... ever...

People still camp - I was under the impression that there were only a few foolish people who still bother to use tents when on holiday but we found quite a few camp sites that were full when we arrived.

You can camp for free in France - As well as the standard service stations on major French roads, there are plenty of aires that are just a bit of land with toilet facilities and running water. We didn't use them ourselves and they are probably only for hardcore campers who are happy to do without modern facilities like swimming pools, shops and showers, but it's good to know they are available if necessary.

Driving is more fun than flying - OK, a 3 hour flight may be quicker and cheaper than a 3 day drive but it doesn't give you any kind of idea of how far you travelled or let you visit any intervening places. 

GPS would be useful - A bog standard map is fine when travelling on the major roads but when you get into a city things can get a bit tricky. If you've got a detailed map of each city you'll visit you'll probably be OK, otherwise GPS will probably make your life easier. I can't verify this since we didn't go for the GPS option. 

The UK should sign up for the Euro - It's surely inevitable so why not go ahead and do it? Life would be so much easier, no more carrying around two currencies, no more trying to work out how much something really costs. So we may lose some sovereignty, so what? Get over it.

Wine in Spain is very cheap - 8 euros for 10 litres...

Wednesday, August 08, 2007

Road trip

It all started when my brother read Trek by Paul Stewart. The book describes the story of four people attempting to cross Africa (including the Sahara) in a Morris Minor during the 50s. Unfortunately it all ended in tragedy. Oddly enough, due to this story, we head out on Thursday on a road trip of our own. Not quite as dangerous as crossing the Sahara (although by all accounts, thanks to GPS, even that journey is much less risky than in the past), we're heading off to Spain to see my dad. The original plan was to go in a Rover P4, but the demands of teenagers mean we have to go in an air-conditioned people carrier.

From a personal perspective, I also see this as part of the slow travel movement. I haven't worked out the figures but I'm hoping this will be better for the environment than flying (although staying at home would be even better of course) and will be much more fun than being crammed on an EasyJet plane.

So move along, there won't be anything to see here for a while.

Wednesday, August 01, 2007

Visual Studio Express 2008

I'm a big fan of the Visual Studio Express 2005 range of products. They cost nothing and are pretty powerful. In some respects they're better than the full-blown version of Visual Studio. They are super quick to load and if you're using FTP to upload ASP.NET web sites, Web Developer is easier to use than Visual Studio. I've been using it for the FreeFlow web site for a while. So I took the plunge and downloaded the beta 2 of the 2008 version of the C# and Web Developer.

First impressions are good. The install was flawless. C# comes with a WPF designer, so I can finally get down to learning that without having to hand-code it. The Web Developer version comes with some AJAX controls so I can play around with them as well. And it's still free.

The question is will there come a time when all Microsoft's development tools are free? We're signed up for the Empower program so they are virtually free for us anyway and presumably lots of other companies are on the same or similar programs. So my guess is Microsoft aren't actually making any money on development tools and with the free tools now being pretty damn good, I'm pretty sure they'll give the full versions away some time soon just to keep us all hooked.

Friday, July 20, 2007

Rain

So there was a bit of rain today, almost enough to flood our house but not quite. And our roof leaked. But the shed is intact. Then as quickly as it arrived, it stopped. And a few hours later, all the evidence had gone. Here are some pictures.IMAG0150 IMAG0155

Wednesday, July 18, 2007

How rich are you?

I've got a theory, not a particularly original theory admittedly, that we all think we're poorer than we actually are (something to do with our celebrity obsessed culture). It only takes a few seconds to plug in some numbers to the Channel 4 Rich-o-meter or The Institute for Fiscal Studies' 'Where do you fit in?' page to see how rich, or otherwise, you are. The Channel 4 one is interesting since it allows you to compare yourself to the rest of the world, which shows even a very modest UK salary is pretty damn good when compared globally. The Institute for Fiscal Studies' version is probably more accurate since it is based on household income rather than personal income.

Tuesday, July 17, 2007

Adding services to the Windows Workflow runtime and a simple activity implementation

There are two groups of Windows Workflow service that you'll come across. The first group are the well-known services that are used by the runtime itself (well-known because they are well-known to the runtime not necessarily to the developer using the runtime...). These are things like the persistence service, tracking service, data exchange service etc. You can use these services out of the box or you can inherit from them and modify them as required. Fortunately a lot of the methods in these services are virtual so you can quite easily hook in new functionality (and quite possibly get yourself in a whole heap of trouble as well).

The second group of services are services that can be used by your own custom activities. At this point it's worth considering when using your own service makes sense. For instance I downloaded an email sender activity that required me to configure the SMTP host address and port as properties on the activity. Since it was a standalone activity, this was probably the sensible option, since it simplified usage. But if I were to use the activity in many different workflows and the SMTP host changed I'd need to update every workflow to work with the new SMTP server. So if I was to write the activity myself it may well make more sense to handle all this kind of configuration in an email sender service. This also has the advantage of being able to pull the plug on emails being sent out if a poorly written workflow was sending out too many emails. So it depends on what you're trying to achieve whether services make sense or not.

To actually add your own service to the runtime is pretty straightforward. Define an interface and mark it with the ExternalDataExchange attribute.

    [ExternalDataExchange]
    public interface ISendEmail
    {
      void Send(string toAddress, string message);
    }

Next write a class that implements the interface.

    public class EmailSenderService : ISendEmail
    {
      public void Send(string toAddress, string message)  
      {
        // send it...
      }
    }

I'm not entirely sure whether you have to use an interface or if you can just use a class straight off but I've only used interfaces myself and there are at least a couple of good reasons why this is the best way to go. First, it decouples your service implementation from the activity that is calling it. For the email sender example, this means you could replace the SMTP sender with a new implementation using Exchange (or whatever) to send the email without needing to change your activity implementation. Second, if you want to use the CallExternalMethod activity to call into the service, this only accepts an interface for the InterfaceType property.

After that, all you need to do is add the service to the runtime.

    // external data exchange service
    ExternalDataExchangeService dataService = new ExternalDataExchangeService();
    runtime.AddService(dataService);
    
    // email sender service
    EmailSenderService emailService = new EmailSenderService();
    dataService.AddService(emailService);

To call the ISendEmail methods, you have two choices, hook up a CallExternalMethod activity or write a custom activity to call the method. Since I've not yet shown an activity that does anything useful, I'm going down the latter route. Create a new activity via the Add/Activity... popup menu item and add some code as follows.

    protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
    {
      // generate alerts
      ISendEmail sendEmail = (ISendEmail)executionContext.GetService(typeof(ISendEmail));
      if (sendEmail != null)
      {
        sendEmail.Send("doogal@doogal.co.uk", "blah");
      }

      return ActivityExecutionStatus.Closed;
    }

This is the simplest activity that you can implement, it executes some code then returns saying "I'm done". When I work out how to implement some more complex activities, I'll write about it.

Monday, July 09, 2007

Blogging is like the lottery

The lottery people Camelot used to say "You've got to be in it to win it". Of course the chances of a big win are tiny but if you never buy a ticket you'll never win anything at all. So it is with blogging, you're pretty unlikely to ever get a big crowd of people to your blog, but occasionally you might get that £10 win. Every post is another ticket in the blogging lottery and every so often you'll get a few hits from one.

Which is what happened with my little post about SonicWall on Vista, if only because nobody else has bothered to post about it. And if anybody wants to know, the latest beta still has the same problems for me, Vista complains that two computers with the same IP address are connected to the network. But I'm coming to expect these kind of issues with Vista. Bring on SP1...

Sunday, July 08, 2007

Annoying Vista UI

In Vista, Media Player and Photo Gallery have very similar user interfaces. The toolbar thingy at the bottom of their windows looks almost exactly the same.

wmp This is Media Player
photo_gallery This is Photo Gallery

But the big button in the middle works differently. If I'm watching a video in Media Player, the biggest button on the toolbar pauses the video. In Photo Gallery, it switches to slide-show mode, an operation that takes several seconds and I never want to do. If I'm not thinking about what application I'm in, I'll hit that big button to pause the video and see my computer grind to a halt whilst it does something I don't want it to do. Why have very similar UIs if the buttons do different things??? Consistent UIs are only any use if they behave consistently.

Thursday, July 05, 2007

The Complicators

I was under the impression that computing was meant to make our life easier, but it seems there's a bunch of people out there who want to make my life more difficult through poorly thought out APIs or badly designed user interfaces. I call them the complicators.

There are three types of complicators.

Dumb Complicators - These are the developers who aren't really too hot at programming. They copy and paste and generally fumble around in the dark until they have a solution that seems to work, then quickly move onto the next problem, not thinking too much about how the UI or API they've just produced will be used in the outside world. This may be down to inexperience, the need to get something out there ASAP or just a lack of interest in producing quality software.

Evil Complicators - The second group of complicators are a cynical bunch who complicate things to make themselves indispensable to their company. Depending on how cynical I'm feeling, I may confuse either of the other two groups as being members of this lot. 

Clever Complicators - The third group are generally incredibly intelligent but have no way of empathising with the poor people who are going to have to use their software. They understand the complexity and can't understand why anybody else wouldn't be able to. I worked with a very clever guy whose API consisted of a programming language using XML to build the function calls, parameters and the graph used to join all these bits together. Yes, he was a big fan of XSLT. Yes, what he produced was incredibly powerful and clever. Actually trying to use his API from another programming language was an absolute nightmare. On the other hand, I worked with another very bright chap whose API was also based on XML. The difference being that his API simply described data and a few parameters. The actual implementation details of how it all worked under the hood was completely hidden from the API, except where necessary. The wonderful thing about that API was that the simplicity of it made me look good, since I was able to write my code on top of it in super quick time.

This third group of complicators interest me. It seems like there are plenty of clever people in the IT industry but a very select few who can actually take complicated problems and abstract them into something simple for the rest of us to understand. And doing that is the only thing that can drive technology forward. As Einstein said "Make everything as simple as possible, but not simpler."

Wednesday, July 04, 2007

Something for the ladies

Or more specifically any mothers who've stumbled across this site. My other half has set up a website dedicated to providing tips for mothers and parents in general. There are other sites out there providing similar resources (Mumsnet being the obvious example if only due to their legal problems with Gina Ford) but Mums Guide is providing a different angle on things.

She was after a link from the Random Pub Finder (due to it getting many more hits than this site) but I couldn't for the life of me think of any kind of link between pubs and parenting.

Tuesday, July 03, 2007

Aren't web services meant to solve interoperability problems?

Somebody has written a web service using JBoss. I'm trying to call it from .NET 1.1 or, heaven forbid, the MS SOAP toolkit. And neither of them can call any operations that have parameters, which kind of restricts what we can do with it. I guess one solution might be to have methods called method1(), method2(), method3() etc all the way up to MAXINT. Doesn't seem a great idea. Or perhaps an ASP.NET 2 web service could call the JBoss web service and expose the functionality as another web service? Yeh it's daft, but it might just work.

So could it be the folks telling us web services were the panacea for all our interoperability problems were actually just snake oil salesmen? Surely not...

Monday, June 25, 2007

Adding icons to custom activities

In a few places I've worked, it seems like some people's jobs pretty much entails selecting and adding icons to development projects. Nice work if you can get away with it and that's what I spent some time doing the other day.

It's actually ridiculously easy to add an icon to a custom activity. In fact it's just the same as adding an icon for any component. Add the image to your project, set its 'Build Action' property to 'Embedded Resource', then add the following attribute to your activity class.

[ToolboxBitmap(typeof(UserActivity), "user.png")]

The icon will then appear in the toolbox and will be shown when the activity is rendered in the workflow designer. It's possible to completely change the rendering of the activity and I may investigate that at a later date, but this simple addition seems to provide the biggest bang for buck.

Sunday, June 24, 2007

Property Snake

I remember Fucked Company appearing on the web around the time of the dot-com bubble bursting so perhaps the appearance of the Property Snake website (along with House Price Crash) is evidence that the property bubble is finally about to burst. That and the more bearish coverage in the press...

Thursday, June 21, 2007

Windows Workflow isn't workflow

Ask anybody who's had any experience of workflow software what it is and they'd likely give you a different answer to the next person you ask. But I'm fairly certain if they took a look at Windows Workflow they'd probably say it's not what they understand workflow to be about.

I'm the same and it's one reason why when I first looked at WF I was a little disappointed. But as time goes on and I play with it more and more I'm realising what a really nice piece of technology it is. In fact I'd say I'm actually very pleased that Microsoft didn't build another workflow system because it very likely wouldn't have met my needs either. There are hundreds of workflow systems out there, all implemented differently from each other and all meeting certain needs and failing to meet other needs.

I guess somebody at Microsoft realised this and rather than producing yet another workflow system (YAWFS for short), they wrote a framework for developing any kind of long-running process you'd like to build on top of it. As far as I'm aware nobody else has tried to come up with anything similar and the outcome is far more impressive than YAWFS. The book 'Essential Windows Workflow' explains it a whole lot better than I can but essentially it's a whole new way of writing software. No longer do you need to worry about what to do when you need to wait for a day before moving onto the next step in your code and it seems like threading issues will be much reduced. I'm almost inclined to think that WF may be the answer to a lot of the multi-threading pain we suffer today and really need to solve PDQ in a world of multi-core processors, although I need to delve deeper to know for sure. If you come from a .NET background, you can reuse those skills in WF, although it has to be said the learning curve can be quite steep. 

And it seems like they've succeeded in their aims. Not only are people using WF for workflow products, they are using it for things that you wouldn't necessarily associate with workflow. In conclusion, I think it rocks.

Wednesday, June 20, 2007

Compiling a XOML workflow

In my last post I talked about validating a XOML workflow. Another way to validate a workflow is to just try and compile it and see what you get back from the compiler. The disadvantage of this approach is the fact you have to start to write things out to file. So I've been validating using the previous method and then just compiling when necessary*. The downside of this approach is the x:Class attribute which can't be present when trying to execute a XOML workflow and must be present when trying to compile it. The simple workaround for this is to add the x:Class attribute before writing the XOML out to a temporary file. Anyway here's the code -

        // copy to a temporary file and add the x:Class attribute
        string tempFileName = Path.GetTempPath() + "temp.xoml";
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(xoml);
        doc.DocumentElement.SetAttribute("Class", "http://schemas.microsoft.com/winfx/2006/xaml", WorkflowName);
        doc.Save(tempFileName);
        try
        {
          // Compile the workflow
          WorkflowCompiler compiler = new WorkflowCompiler();
          WorkflowCompilerParameters parameters = new WorkflowCompilerParameters();
          parameters.LibraryPaths.Add(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
          parameters.ReferencedAssemblies.Add("MyActivities.dll");
          parameters.OutputAssembly = string.Format("{0}.dll", WorkflowName);
          compilerResults = compiler.Compile(parameters, tempFileName);
        }
        finally
        {
          File.Delete(tempFileName);
        }
        
        StringBuilder errors = new StringBuilder();
        foreach (CompilerError compilerError in compilerResults.Errors)
        {
          errors.Append(compilerError.ToString() + '\n');
        }

        if (errors.Length != 0)
        {
          MessageBox.Show(this, errors.ToString(), this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
          compileOK = false;
        }

* Another reason I did it this way was because I implemented the validation piece before I implemented the compilation piece and didn't realise I could just re-use the compiling code...

Tuesday, June 19, 2007

Validating a XOML workflow

If you're using workflow assemblies, there is no need to validate your workflow since the compilation process has already done this for you. But if you're working with XOML files you'll probably want to validate it at some point before deploying it. Unfortunately there doesn't seem to be anything provided by Windows Workflow just to validate a workflow. The workaround is to start up the runtime and load up your XOML and see what errors you get. You can use something like the following (ripped off and modified from a newsgroup posting) -

      WorkflowRuntime workflowRuntime = new WorkflowRuntime();
      workflowRuntime.StartRuntime();

      StringReader stringReader = new StringReader(xomlString);
      XmlTextReader reader = new XmlTextReader(stringReader);
      try
      {
        instance = workflowRuntime.CreateWorkflow(reader);
      }
      catch (WorkflowValidationFailedException exp)
      {

        StringBuilder errors = new StringBuilder();

        foreach (ValidationError error in exp.Errors)
        {
          errors.AppendLine(error.ToString());
        }

        MessageBox.Show(errors.ToString(), "Validation errors");
        retVal = false;
      }

One thing to be aware of is that you can't add the x:Class attribute when you use this technique (which you must add if you want to compile your XOML later on). This Catch-22 can be quite easily solved and I'll talk about it in a later post.

If you're wondering why you'd use XOML, I think it probably makes sense when you're automatically generating your workflows from some other source.

Invalid FORMATETC structure (Exception from HRESULT: 0x80040064 (DV_E_FORMATETC))

I've been caught out by this twice now. If you create a new web control by creating a new class and then inheriting from Control (or some other derived class) it will appear in your toolbox, but when you try and put it on a web form, either nothing happens or you'll get the error:

Invalid FORMATETC structure (Exception from HRESULT: 0x80040064 (DV_E_FORMATETC))

This somewhat baffling error message is caused by the fact that when you create a new class Visual Studio 2005 makes it private by default. I'm not sure if this is a good or bad thing, it sure as hell beats the "everything is public, every parameter is passed by reference, every variable is a variant" ethos that used to cause so much horrendous VB code to come into existence. Just a shame the error message doesn't give a clue to the real problem.

Implementing your own workflow type in Windows Workflow

Windows Workflow is extensible in almost every way. But one thing I didn't realise until seeing this example is that it is possible to implement your own workflow type as well. This looks really interesting. Although the state machine workflow models what I want to do pretty well, I'm not too happy with the UI of the designer so I might have to look into this further.

Saturday, June 16, 2007

Validator for a custom activity in Windows Workflow

Last time I talked about adding a property to a custom activity, this time I'll talk about validating the value of that property.

So we have a custom activity called UserActivity with a property called Form and we want to ensure the workflow designer has specified a value for this property. First thing to do is write our validator class, which looks like this - 

  class UserActivityValidator : ActivityValidator
  {
    public override ValidationErrorCollection Validate(ValidationManager manager, object obj)
    {
      UserActivity activity = (UserActivity)obj;
      ValidationErrorCollection validationErrorCollection = base.Validate(manager, obj);

      // Don't validate when the activity is standalone  
      if (activity.Parent == null)
      {
        return validationErrorCollection;
      }
      
      // check Form property has been set
      if (string.IsNullOrEmpty(activity.Form))
        validationErrorCollection.Add(ValidationError.GetNotSetValidationError("Form"));

      return validationErrorCollection;
    }
  }

All we do is override the Validate method, call the base implementation, then check to see if the activity has a parent. This check ensures we don't validate the activity when we are designing and coding the activity itself. The next line does the actual work, using a helper method provided by the ValidationError class. This can be used in the most common type of validation, checking to ensure the property has a value. If that's not what you're doing, create an instance of the ValidationError class instead, using whichever constructor you need. 

Once we've written the class all that remains is to tell WF what class should be used to validate the activity, which we do by adding an attribute to the activity declaration.

[ActivityValidator(typeof(UserActivityValidator))]
public partial class UserActivity: HandleExternalEventActivity

And that's it. Now compiling a workflow assembly using the custom activity should show a compiler error if the Form property has not been set.

Friday, June 15, 2007

Activity properties in Windows Workflow

I initially thought Windows Workflow was horrendously complicated, needlessly so. I've since realised that it's just exceedingly extensible but one problem is that there aren't a great deal of internet resources to search through to find the answer. No surprise I guess since this is pretty new technology. So I've decided to add some little tidbits. I'll present a few very short posts about a very small subset of the functionality, a kind of Windows Workflow for dummies. Given that I'm a dummy myself, I am perfectly placed to do this I reckon. Of course since I'm still learning all about WF, these posts may be incomplete or plain wrong.

So first up, adding a property to a custom activity. Properties in WF don't work like properties in normal .NET classes, they are based around dependency properties, which are properties that can be attached to any class deriving from DependencyObject. All activities inherit from DependencyObject so they can use dependency properties. I believe dependency properties must be used when you want to let your workflow designers be able to bind their properties together. Normal properties would have no way of knowing how to update other bound properties when their value had changed.

What is probably worth mentioning at this point is that WPF also uses dependency properties and dependency objects. They look very similar to the WF ones, but they are defined in a different place (System.Windows for WPF, System.Workflow.ComponentModel for WF) so I can only assume there are some subtle differences between the two.

Anyway, here's some code for a simple WF property.

    public static DependencyProperty FormProperty = DependencyProperty.Register("Form", typeof(string), typeof(UserActivity));
    
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    [Browsable(true)]
    [Description("The form to be displayed when the user initiates the activity")]
    public string Form
    {
      get
      {
        return ((string)(base.GetValue(UserActivity.FormProperty)));
      }
      set
      {
        base.SetValue(UserActivity.FormProperty, value);
      }
    }

So we have a custom activity called UserActivity with a property called Form. It looks like a normal property except the getters and setters use the GetValue and SetValue methods defined in the DependencyObject class. Beyond that all we need to do is register the dependency property. Once that is done, the property should appear just like any other in your workflow.

Thursday, June 14, 2007

Metastorm BPM 7.5 review

It's been around a while so it's about time I wrote down my thoughts. If you want to see the official line take a look at the Metastorm Press Release, I'm just going to talk about things that interest me, which in general means the core product and any .NET integration pieces.

One of the main reasons I wasn't particularly keen on version 7.0 was the requirement to disable DEP before installing. Although this was rectified in the first service release, installing still required disabling DEP, installing 7.0, re-enabling DEP then installing the service release. Thankfully this has all been fixed in 7.5 and I presume 7.5 can be installed straight over 6.6, although I haven't tried this yet.

I've been running with 7.5 web client against some 6.6 engines to get a feel for it. Although this isn't supported and it does seem to have a few issues, it's pretty useful for testing out the various client-side hacks we've employed in the past. There's not been any major innovation in the web client but it has had a few minor tweaks and I'm very much of the opinion that small things matter. The things I like are

  • the ability to kick off an action without opening the folder, this is a quite a productivity boost.
  • fixed headers on a grid. I'm sure it took an afternoon to implement but it will please many many people.
  • the error message when a required field has not been populated tells you the name of the field. Again, a minor change but shows someone is paying attention to the details

You can also add links from the web client to other sites. It's seem a bit of a random feature but I'm sure some people will love it.

The Designer on the other hand seems somewhat unloved, which is understandable given Metastorm have started on a complete rewrite of it. There aren't really any new features to speak of (except the .NET event delegation which I'll talk about shortly). There are some serious performance issues when using it, it seems to flicker constantly when moving around and adding fields to a form takes forever. I've had it crash a few times but I'm not sure it's any less stable than previous versions. The pointless dialog count is about the same, although I did find a new one when it couldn't locate the ELB file in the database so it asked if it should look for an XEL instead. Yes of course you should, do you really need to ask???

So onto the .NET integration. Initially I thought this was pretty poor but upon closer examination it is actually reasonably good. Tell the Designer you want to delegate your map events to a .NET assembly then go into Visual Studio and create an assembly for the map via a wizard. I thought this was the end of it, which left me wondering what would happen when I updated the procedure. It turns out there is some integration with Visual Studio but the installer didn't activate the add-in. Once I had that running, I was able to synchronise the procedure and assembly and deploy it.

There's a few problems with this integration though

  • not all events are covered. When button pressed and when the user selects a row in a grid are the obvious ones, but calculated fields and basically all places where e-Work formulae are used need to be available.
  • deploying the assembly requires stopping and starting the engine. Oddly, Metastorm have worked around this by stopping and starting the engine for you from Visual Studio rather than going down the more obvious route of using shadow copies. This is fine for a development machine but deployment to a production machine would be much easier without this requirement. ASP.NET has been doing it for years...
  • I think the Process Orchestrator requires a separate license purchase. Really this should be part of the main product and until it is, I don't think we'll be interested in using it.

.NET 3, worst... name... ever...

People have got their fingers burned in the past. Installing .NET 2 did cause some applications to break (OK, I can only think of Metastorm e-Work off the top of my head but most people I deal with are using that bit of software) so every time I tell them to install .NET 3 to use the wonders of Windows Workflow I have to include a disclaimer that .NET 3 isn't really a new version of .NET, it runs on top of .NET 2 so shouldn't break anything blah blah blah. Worst... name... ever...

Monday, June 11, 2007

Browsers getting interesting again

Well interesting is perhaps stretching it, but certainly confusing. IE7 has been out for a long time now and it seems to have stalled at about 30% usage. Then today Apple released a version of Safari for Windows. So now I have yet another browser to worry about, because I'm guessing quite a few people will start using it, because it's not Microsoft. Yeh, it's based on Mozilla but it's bound to be different to FireFox and it's bound to be different to Safari on the Mac.

And IE7 doesn't make life any easier. I can't forget about IE6, because most people are still using it, but enough people are using IE7 that I can't ignore that either. I will however continue to ignore Opera, Konqueror, Lynx, Netscape and any older versions of IE. Complain if you like, but I have better things to do with my time than worry about browsers with miniscule market share.

Friday, June 08, 2007

House prices to reach ten times salary? Bollocks

According to a report from a government think tank, house prices may be 10 times average salaries by 2025. It's all down to supply and demand apparently. Sure, looking at the figures in a simplistic fashion, with an increasing population and inadequate house building then house prices should continue to increase. But think about it a little longer and it clearly doesn't make any sense. Who will be buying these houses? First time buyers are already priced out of the market. Buy to letters might take up the slack but only if rents rise in line with house prices, otherwise they'd be better off investing their money elsewhere. So will rents rise as well? Given that a lot of our increase in population is driven by economic migrants, who generally are in pretty poorly paid jobs and renting, if rents rise dramatically, will they continue to come here? Probably not, since they'll be better off staying at home. So demand won't increase, meaning prices fall back to a more sensible level. There's also the question of whether the indigenous population would hang around with such ridiculous prices, meaning even less demand for housing.

On reflection, I suspect this report is purely some spin to get the idea of relaxing planning laws onto the agenda, thus enabling more house building. But whatever it's about, it's bollocks.

Wednesday, June 06, 2007

Great photo

IMAG0115How come my 4 year old daughter can take better photos than me? I have no idea what this is a photo of but I love it. She is also available for designing Olympics logos.

Tuesday, June 05, 2007

Bye bye eBay, hello Freecycle

I've sold lots of my old crap on eBay, but I've got a little fed up with it. Most of the stuff I've sold isn't high value so the hassle of eBay just isn't worth it. It takes a long time to put together the sale details, take pictures and package the item and post it. Then eBay takes their cut (whether you manage to sell your item or not) and PayPal takes a cut. Then there are the problem buyers, who fail to pay or have to be chased up. So for quite a lot of work, the returns are pretty slim.

So I've given up on it and I'm going to start giving stuff away on Freecycle. All I need to do is post a message and hopefully get a response. It has the added advantage of working at the local level, so goods aren't going to be transported half way across the world. Apparently there are over 3 million users already, pretty impressive.

Friday, June 01, 2007

Ah, so flickr does have a business model

I'd always presumed flickr was one of the web 2.0 sites that seemed to think it could somehow make money out of thin air. Then I was uploading some photos from the Random Pub Finder when I hit the site's 200 picture limit. Of course I can upgrade to a Pro account, but really it's not worth it for me. The only reason I was using flickr was to get some inbound links to the RPF and that isn't worth $24.95 a year. Because RPF's business model is non-existent...

New version of Windows Live Writer

livewriterThere is a new version of Windows Live Writer available. It looks prettier and has squiggly line spell checking but beyond that I don't know if it offers a lot. My problems with Live Writer in the past has been its inability to upload pictures to Blogger (which by all accounts is Blogger's fault) and its inability to check for new versions. I only found out about this new version after stumbling across a review of it. Admittedly, programs that do check for updates tend to upset me as well since they seem to require a new install every time I run them, so there's no pleasing me...

Anyhoo, I'll see if it uploads images now.

Time passes...

OK, so it can't upload images to Blogger directly but it will upload them to an FTP site and hook them into the page. The FTP integration is pretty sweet, although I guess it'll be no use to a lot of punters. But it solves my problem.

So that and the squiggly line spell-checking means I'll give it the thumbs up, even if it can't spell colour.

Some more time passes...

OK, perhaps I should have used the thing before writing a review. It now supports Blogger tags as well, meaning I'll now very rarely need to use the Blogger web interface, so even more thumbs up.

Thursday, May 31, 2007

A grey water experiment


We are constantly told that investing in a water butt to water our gardens is a good thing, it saves water and hence the planet. What is never mentioned is the fact that when you need it most, your water butt is probably not going to be much use to you. When it hasn't rained for several weeks and the inevitable hose-pipe ban is in place, you water-butt won't have a drop of water in it. Because of this, my water butt isn't getting filled up with rain water. Although the general consensus seems to be that using grey water for watering your garden may not be a good idea, as ever I decided to ignore any advice given to me and hooked our water butt up to the outlet from our bathroom. I'm not sure all houses are configured like ours, but the used water from our sink and bath goes out through a couple of pipes into a drainpipe so using this for the water butt was very simple.


And it seems to work fine. The water can smell a bit, but it doesn't seem to kill our plants and we can water the garden without feeling any guilt. One thing, remember not to wee in the shower... Although I'm sure you'd never do such a thing.

Wednesday, May 23, 2007

More on JScript exceptions

I don't know much about JScript, so when I need to find out anything I head off to Google. So that's what I did when I wanted to know about throwing exceptions. Almost every example I've seen shows something like - 

throw "something went wrong";

Initially I thought this would be wrapped up as an exception by the JScript runtime, but it turns out it is actually a string that gets thrown. Which may be fine in some cases. The problem comes when you want to catch exceptions. If you want to catch all exceptions thrown in a bit of code (yeh I know, bad idea, but this is JScript not software engineering...) then things will get complicated. The runtime will throw exceptions but your own code is throwing strings, so you have to deal with them differently. Turns out the solution is pretty straighforward -

throw new Error("something went wrong");

Now everything is an exception and life is good.

As a side note, I've not considered throwing anything other than an exception before. C# doesn't allow it, although I guess IL probably does since it needs to support JScript.NET. Delphi partially allows it, you can throw any object you like but not strings since they aren't proper objects in the Delphi world. But it's not clear to me why you'd ever want/need to do it...

The new Google Analytics

So there's a new version of Google Analytics available which is lovely and shiny and new. But they seem to have removed the ability to show data by month or hour. Monthly data is useful to get an overview of how traffic is increasing/decreasing over time, since daily data is too volatile. Hourly data is great to see what's happening on your site today.

Tuesday, May 15, 2007

Why I'm not using UAC

Lots of people keep saying I should switch User Access Control on. So I thought I'd give it a try since I wanted to see how painful it was or if it was actually not so painful after all. And of course I'd like my software to run with UAC enabled without causing any issues.

But here's the problem. Vista is already screwed up on my machine, what with no sound, a SonicWall VPN client that screws up TCP/IP and complete machine freezes every couple of days. And UAC makes it even worse! Internet Explorer has some serious problems when UAC is enabled. It won't print, links that open new windows don't work and the dropdown menu on the back button doesn't work. Explorer always opens folders in a new window, even though it is set up to reuse the same window. Lots of applications won't work at all unless I run them as administrator (Visual Studio being the obvious example) which rather defeats the point of UAC. And these are the problems I've found after using UAC for about two days so there are bound to be more.

And of course I've not even mentioned the annoying dialogs that appear fairly regularly to disrupt my workflow.

So in principle using UAC may be a good thing and dogfooding it constantly with my own code would be a nice thing to do, but in practice it is too painful and I'm putting it back in its box until SP1 comes out. 

Monday, May 14, 2007

How the web was won

In one of my previous jobs I was responsible for helping to develop a native Windows client. At the same time, a web client was developed by another team. Although the native client had some advantages (it was much quicker and generally more reliable*), the web client was much more successful. I suspect this was mostly down to the deployment issues you have with a native Windows client. Even now in a world of ClickOnce deployment, web clients are still preferred by a lot of customers.

But one thing that has become apparent to me since doing more integration work is that web clients also have one other major advantage over native clients. Whether you intend to or not, when you develop a web client you get a plugin architecture for free. Doing the same thing in a native client takes a lot of thought and development time, but anybody can hack around with a web client to make it look like they want or do what they want, via CSS, Javascript or even server-side hacks with some systems. Yeh, these hacks may well break between releases, but it still makes web stuff very attractive to integrators. To do the same thing in a native client would likely involve going back to the vendor to ask for a change in functionality or an extensibility point where code can be plugged in, which might take months, rather than an afternoon of fiddling around. And that I reckon is the killer reason why the web has won.

* This was no reflection of the development team working on the web client. It's just that, all other things being equal, writing a native Windows client is much simpler than writing a web client.

Tuesday, May 08, 2007

Virtual Earth vs Google Maps part 3

Many moons ago I tried out Windows Live Local (now called Virtual Earth I think) and decided it didn't meet my needs since it didn't show any London tube stations or train stations which made getting round London kind of difficult. I checked it out again today and it now has got tube and train stations. This is actually a step ahead of Google Maps that only show tube stations. However it seems to be a bit buggy currently since sometimes stations appear at one zoom level, disappear when you zoom in, then re-appear again after more zooming, which I presume is not by design. Check out Herne Hill.

So finally these Web 2.0 sites have almost caught up with Streetmap, which I don't think has been updated in about 5 years. Kind of shows up the 'we move in a fast moving industry' mantra as a complete lie.  

Friday, May 04, 2007

Even more on tick marks in HTML

It's always the seemingly simplest probems that have the most long-winded solutions. So my last post was wrong, although that solution worked in some HTML docs, as soon as I switched to HTML 4.01 FireFox started showing extra crud, as you'll notice if you're viewing this in FireFox. So here's a solution for tick marks in HTML 4.01, still using conditional comments, which works in IE6, IE7 and FireFox 2, probably...

<![if !IE]> &#10003;<![endif]>
<!--[if IE 7]> &#10003;<![endif]-->
<!--[if lt IE 7]> <input type="checkbox" disabled="disabled" checked="checked" /> <![endif]-->

And to complete the whole thing, here's an XSLT template to put a tick mark in your HTML output.

  <xsl:template name="outputTickMark">
<xsl:text disable-output-escaping="yes">
&lt;![if !IE]&gt; &#10003; &lt;![endif]&gt;
&lt;!--[if IE 7]&gt; &#10003; &lt;![endif]--&gt;
&lt;!--[if lt IE 7]&gt; &lt;input type="checkbox" disabled="disabled" checked="checked" /&gt; &lt;![endif]--&gt;
</xsl:text>
</xsl:template>

and here's a tick mark that might work this time.



By the way, I found this article on conditional comments particularly useful.

Update: The absolute final word on this subject is here

Wednesday, May 02, 2007

More on tick marks in HTML

My original post about displaying a tick mark in HTML is one of the more popular hits on this site. This fact and the increasing usage of IE7 and FireFox drove me to come up with a nicer solution than the one proposed there (using the lowest common denominator checkbox input field).

Internet Explorer supports something called conditional comments. Using these you can serve up different content to different browsers directly in your HTML, rather than doing funky server-side things. I have to use this approach since I'm generating a static HTML file. So here is the markup -

<!--[if IE 7]><!--> 
&#10003;
<!--<![endif]-->
<!--[if lt IE 7]>
<input type="checkbox" disabled checked>
<!--<![endif]-->

The if IE 7 comment will be rendered by IE7 and any other browser. The if lt IE 7 comment should only be rendered by IE6 and below. I've tested it in IE6, IE7 and FireFox 2, which covers enough bases for my needs. And here is the output, which hopefully should show some kind of tick mark.


Update - there's a more up to date and correct version of this available here

JScript try catch syntax

I alway forget the syntax for JScript exception handling and searching on the web always seems to bring up the wrong thing, so here is an example as my own personal reminder.

    try
    {
        // do stuff
        return "blah";    
    }
    catch(e)
    {
        return e.message;
    }

Yeh, I know, I should be able to remember that... I blame it on the crap JScript editors, none of which provide the mental crutch of code completion.

Remember too, JScript requires the e, you can't use catch().

Sunday, April 29, 2007

SonicWall VPN Client for Vista beta

One of the problems I've had with Vista is the fact the SonicWall VPN Client doesn't work with it and SonicWall haven't released a new version for Vista. Well they've finally got their arse in gear and released a beta version of the VPN client.

Send an email with “subscribe” as the subject of the email to gvc40-join@listserv.sonicwall.com if you’re interested in participating in the beta program.

It kind of works for me, although after a while Vista complains that two PCs are connected to the network with the same IP address. Then everything falls apart. Restarting the VPN client and my wireless connection fixes the problem.

Addendum (28th October) - The SonicWall VPN client for Vista is now out of beta and it is all working fine for me now.

Phew, it's not just me

First off, Canary Wharf is one weird place. I haven't been there for a while but it's almost like it has a dress code, everybody is wearing a suit, or shirt and trousers at the very least. So when I rolled out of the station in my old jeans with a few days facial hair growth I thought I'd be picked up by the police as a terrorist suspect. Fortunately I didn't bump into any police men. I was fairly sure Credit Suisse wouldn't let me in either but perhaps they'd been warned that a group of geeks was visiting.

I was attending a London .NET User Group meeting for a talk about Windows Workflow. The first part of this talk was reasonably interesting, although it was clear the presenter has been reading the same book as me, so a lot of it wasn't new to me. But things got interesting when one of the guys who's been developing a WF application at Credit Suisse talked about their experiences. The things that came up were pretty much the same issues that I've come up against.

First, the versioning story just isn't there yet. Storing serialized objects in the database means upgrading workflows can be somewhat tricky, since after an upgrade the deserialization is unlikely to work. Which is why I think using serialization is generally a bad design decision, unless the life of the serialized objects will be very short (copying to the clipboard, sending an object across the wire etc). So they've been forced to write some code to get pertinent information from the live workflow, destroy the instance and recreate it using the new workflow version and re-assign the state data.

The second problem is actually caused by the same issue. You might think since the workflow is stored in a SQL Server database, you could just query it to find all the instances that have a particular property, but again the fact that the worklfows are opaque blobs means this isn't possible. They worked around this by extending the persistence service to store relevant data relationally whenever a workflow is persisted.

It's nice to know that most problems can be worked around. There is so much flexibility in the WF hosting and runtime that almost all of the default implementations can be re-implemented to do what you want. I just hope this doesn't lead to Microsoft not fixing what are clearly problems with the default implementations.

One final thing that was mentioned that I was coming round to thinking myself is that state machine workflows are actually the way to go for many kinds of problems. Most of the talk in books and the web seems to be about sequential workflows but I think state machines are actually a better way to go most of the time. Of course this may just be due to my background in Metastorm e-Work which uses something closer to a state machine than a sequential workflow.  

Friday, April 27, 2007

More Vista pain

I finally cracked. I'd had enough of the complete lack of support from Dell about my lack of sound on Vista. The guy said he'd get back to me, of course he never did. Emails to Dell got no response. Yeh I could kick off another support call but it would just involve several hours of them uninstalling and installing drivers and failing to get anywhere, which I've been doing pretty well myself for several months. To top it all off, Dell sent me an email asking me to fill in a questionaire about my customer service experience. When I clicked on the link, all I got was a message telling me my access had expired. They even sent me a reminder to fill in the survey a few days later, again access expired. Hey Dell, there may be a reason you're not getting much feedback on your customer service...

So I thought, stuff this I'll buy a new soundcard, £20 and all my pain will go away. It all started out really well, Vista recognised it, went away to find the drivers and everything installed correctly, or so it said. Then I tried to actually get some sound out of the PC, nothing, nada, zilch. I pressed the dreaded 'Test' button, 'Failed to play test tone'. Aaaagh! Cheers Vista, why couldn't you play the test tone? I almost long for the usual massive hex number, at least something to work from. The event log is empty.

So now I have no idea what the problem is caused by. Presumably it isn't a driver or hardware problem, so is my Vista install broken? I really don't want to reinstall the whole thing.

On another note, Vista has developed a nice habit of locking up completely, the mouse stops moving, the keyboard doesn't respond, CTRL-ALT-DEL does nothing, the only thing I can do is hit the reset button.

Five years, thousands of developers and what do we have? A prettier version of XP that for me is less stable and other than IIS 7 doesn't really offer much new.

Tuesday, April 24, 2007

Recruiters - how about reading my CV?

I'm not looking for a job currently but my CV must be out there somewhere on the internet from the last time I was looking for work. And it's pretty clear quite a few recruiters just do a keyword search and send out emails without actually ever reading my CV. So I've had emails about C++ positions, which I haven't touched for almost 10 years, PHP jobs, which I'm familar with but wouldn't consider a strong point, testing jobs and even jobs in the US.

Maybe the 'throw enough shit at the wall and some of it will stick' technique works but I suspect it's not highly effective. I tend to remember the recruiters who actually bother to ring me up and actually listen to what I have to say and if I ever need to contact a recruiter again I'll go to them first, since they appear to care about placing people in the right job. The others are simply helping to confirm the bad reputation that recruiters have.

Monday, April 23, 2007

The ZX Spectrum is 25 years old

And how old does that make me feel?* Get an emulator and download some great games at World of Spectrum, read more about the mad genius Clive Sinclair at Wikipedia.

* Short answer - very

Friday, April 20, 2007

How to solve virtually any technical problem

People ask me technical questions all the time. I have no idea why, I don't know any more than anyone, perhaps the fact I can find the answer to these problems leads people to think I actually know the answer. So I'm going to present to you the two steps to find the solution to almost any technical problem.

Google for it - The internet holds the answer to pretty much any question you can ask. The key to finding the answer is to know how to search. This is pretty much trial and error, if one search doesn't bring up the answer, try another phrase until you get something that looks related. If you're getting a specific error message, search for that.

Another point to make here is that if you can't find what you're looking for, consider whether what you're trying to do is a good thing to be doing. I remember trying to find information about hosting .NET WinForms controls in Internet Explorer and not having much luck at all. This was a big red warning light to me that perhaps even attempting to do this kind of work was a bad idea since it would appear very few other people were doing it.

Infinite monkeys - You know the saying, given an infinite number of monkeys with an infinite number of typewriters and infinite time, one of them will produce the works of Shakespeare. So it is with fixing technical problems. Try enough things and one of them will be the right answer. The key to this technique is only to make one change at once, otherwise one of your changes may fix the problem and your other change might break it again. Or you forget one of the changes you made and don't set it back to what it was before and you're in an even worse position.

So now I've given you the tools, you don't need to bother me anymore, OK? 

Tuesday, April 17, 2007

Buy less crap

The idea touted by Red that somehow we can help charities by buying more stuff is frankly preposterous. The idea put forward by Buy (Less) Crap is to not purchase more consumer tat and donate the money we would have spent to charity instead. Now that seems much more sensible. How many fecking iPods do we need anyway?

Monday, April 16, 2007

Doogal's guide to parenting

You can read every book by Gina Ford you want but from my vast experience (ahem) there are only two things you need to master when bringing up a child.

Bribery and blackmail. 

Friday, April 13, 2007

No really, total rewrites don't make sense

I just found this fairly old blog post about rewriting Delphi apps in C# which sits so well with how I think (and puts the point across far more eloquently than I could ever do) that I had to post the link.

The bottom line is if you have an old code base to maintain, rewriting it completely may seem like an attractive option, but there are other ways of getting to the same place without throwing away years of investment in that old code base.

Wednesday, April 11, 2007

Swimming to New York

I'm not the first person to point out the humorous suggestion from Google Maps when you ask for directions from the UK to the US (see step 36), but it got me thinking.

One of the shortcomings of Google Maps is that it has no knowledge of anything but driving so it won't advise me to jump on a plane if I want to get to the US. For that matter if I ask it how to get to London Waterloo from my house, it doesn't know anything about trains so again will tell me how to drive there. It doesn't know anything about congestion charging or parking charges either so doesn't realise only the super rich or super stupid would ever consider driving into central London.

Transport for London has the opposite problem because it completely ignores the driving option, which in some circumstances might make sense (try taking public transport from SW London to SE London without dying of old age on the way for instance).

A while ago I wanted to investigate transport options for getting to my dad's house in Spain. Here things get even more complicated. There are loads of different websites with information about planes, trains and ferries but I had to find them and then compare prices, times etc.

But none of this stuff is properly integrated. The data is mostly available so it just requires an uber geek to figure how to build a mashup site that takes data from all these different sites and pulls it together in one place. I need to be able to enter a start location, an end location and then be able to get results sorted on which is cheapest or fastest or most environmentally friendly and lets me buy all the required tickets. Presumably if somebody did make such a thing, they could probably finance it by getting commission on the bookings.

And another thought, my guess is one of the reasons people who may be concerned about the environment still take flights rather than taking the overland option is that it is so much easier to book a flight than to book the alternative train and ferry. Oh, and cheaper... Er, and quicker... But at least this site could remove one obstacle.

So, any takers?

Tuesday, April 10, 2007

Maintainable XSLT

Doing a search on Google for 'maintainable XSLT' doesn't throw up a great deal but it seems like something that is really needed. There seem to be lots of resources out there telling me how to code in XSLT, but I haven't found any telling me how to do it elegantly or testably (is that even a word?). I've been working on and off on a project that takes an XML file and spits out a HTML representation of it. When I started off I decided to go with XSLT, rather than generating the output in C# using an XmlWriter. I still think that was the right decision. Even though XSLT is pretty verbose, generating HTML any other way isn't too concise or pretty either.

It's not a big XSLT file by any means (about 1500 lines), but I'm already finding it hard to manage and the tool support just isn't there. Visual Studio 2005 is a step up from 2003, but there are still plenty of things missing. There doesn't seem to be a way to get an overview of an XSLT file by showing what templates are in it. This means some of the possible advantages of splitting it out into separate templates are lost. But even if I was to split it out into separate templates, the markup required to call a template means the XSLT file might actually get bigger due to the calls to the templates!

Another thing I'd like to see is the ability to go to the definition of a template from a call-template call, but that doesn't seem to be available. How about regions, like in C#? OK, I want all the features of the C# editor in XSLT, am I barking up the wrong tree? XSLT is fairly different to C# and I'm coming at this with the mindset of a C# programmer but are there different ways of handling this complexity? Where should I be looking for this information?

Wednesday, April 04, 2007

Method calls on value types and boxing

It was DevWeek 2005 and I was in a session with Jeff Richter about low level .NET things and I foolishly asked him a question. He looked at me as if I had asked the most dumb question ever asked by anyone, so I decided not to follow up on my question, even though I didn't feel he'd really given me the answer I was looking for.

So what was the question? Well he was describing boxing of value types and how it can cause performance problems so it was best to avoid it where possible, even though it's not always clear when boxing is occurring. I'd asked didn't boxing need to occur for any method call on a value type. On reflection I'm not sure this was a particularly dumb question but I've never really got fully to the bottom of it, mainly because it's never really been much of an issue to me. But here's my take on it, which may or may not be accurate. Boxing is only going to happen if the method call is a virtual method where the value type doesn't override the base object implementation. Now it might be boxing would also be required if the value type did override the base method (assuming boxing is required to get the virtual method table), if value types could be inherited from. But they can't so the discussion is kind of irrelevant. This may well be why value types can't be inherited from, but this is all frankly getting way too complicated for me to understand, so I'll quickly move on.

Anyway to illustrate the point, here's a little test C# application.

namespace ConsoleApplication2
{
  struct ValTypeTest
  {
    int val;

    public ValTypeTest(int val)
    {
      this.val=val;
    }

    public override string ToString()
    {
      return val.ToString();
    }
  }

  class Class1
  {
    [STAThread]
    static void Main(string[] args)
    {
      ValTypeTest thing = new ValTypeTest(34);
      Console.WriteLine(thing.ToString());
      Console.WriteLine(thing.GetHashCode());

      int number = 34;
      Console.WriteLine(number.ToString());
      Console.WriteLine(number.GetHashCode());

      Console.ReadLine();
    }
  }
}

If you look at the IL code for this in Reflector using .NET 1.1 (I'll explain why I'm using .NET 1.1 shortly), you'll see this -

.method private hidebysig static void Main(string[] args) cil managed
{
    .custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
    .entrypoint
    .maxstack 2
    .locals init (
        [0] valuetype ConsoleApplication2.ValTypeTest thing,
        [1] int32 number)
    L_0000: ldloca.s thing
    L_0002: ldc.i4.s 0x22
    L_0004: call instance void ConsoleApplication2.ValTypeTest::.ctor(int32)
    L_0009: ldloca.s thing
    L_000b: call instance string ConsoleApplication2.ValTypeTest::ToString()
    L_0010: call void [mscorlib]System.Console::WriteLine(string)
    L_0015: ldloc.0 
    L_0016: box ConsoleApplication2.ValTypeTest
    L_001b: callvirt instance int32 [mscorlib]System.ValueType::GetHashCode()
    L_0020: call void [mscorlib]System.Console::WriteLine(int32)
    L_0025: ldc.i4.s 0x22
    L_0027: stloc.1 
    L_0028: ldloca.s number
    L_002a: call instance string [mscorlib]System.Int32::ToString()
    L_002f: call void [mscorlib]System.Console::WriteLine(string)
    L_0034: ldloca.s number
    L_0036: call instance int32 [mscorlib]System.Int32::GetHashCode()
    L_003b: call void [mscorlib]System.Console::WriteLine(int32)
    L_0040: call string [mscorlib]System.Console::ReadLine()
    L_0045: pop 
    L_0046: ret 
}

As you can see, the call to GetHashCode causes the value type to be boxed, whereas the call to ToString doesn't, because ToString has been overridden whereas GetHashCode hasn't been. But if we look at the IL code in .NET 2, it looks like this

.method private hidebysig static void Main(string[] args) cil managed
{
    .custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
    .entrypoint
    .maxstack 2
    .locals init (
        [0] valuetype ConsoleApplication2.ValTypeTest thing,
        [1] int32 number)
    L_0000: nop 
    L_0001: ldloca.s thing
    L_0003: ldc.i4.s 0x22
    L_0005: call instance void ConsoleApplication2.ValTypeTest::.ctor(int32)
    L_000a: nop 
    L_000b: ldloca.s thing
    L_000d: constrained ConsoleApplication2.ValTypeTest
    L_0013: callvirt instance string [mscorlib]System.Object::ToString()
    L_0018: call void [mscorlib]System.Console::WriteLine(string)
    L_001d: nop 
    L_001e: ldloca.s thing
    L_0020: constrained ConsoleApplication2.ValTypeTest
    L_0026: callvirt instance int32 [mscorlib]System.Object::GetHashCode()
    L_002b: call void [mscorlib]System.Console::WriteLine(int32)
    L_0030: nop 
    L_0031: ldc.i4.s 0x22
    L_0033: stloc.1 
    L_0034: ldloca.s number
    L_0036: call instance string [mscorlib]System.Int32::ToString()
    L_003b: call void [mscorlib]System.Console::WriteLine(string)
    L_0040: nop 
    L_0041: ldloca.s number
    L_0043: call instance int32 [mscorlib]System.Int32::GetHashCode()
    L_0048: call void [mscorlib]System.Console::WriteLine(int32)
    L_004d: nop 
    L_004e: call string [mscorlib]System.Console::ReadLine()
    L_0053: pop 
    L_0054: ret 
}

Now it's no longer clear whether boxing occurs or not, because both calls use the IL constrained opcode. It would appear this opcode has been added for a variety of reasons, but one of them is to help with binary compatibility, so if a value type changes so it adds an override for a virtual method or removes an override, it will still work without any changes to the calling app. The downside of this is that boxing is even more hard to spot than it was before.

Saying that, worrying about boxing is often not really worth the trouble. It smells of premature optimization and in most cases isn't likely to cause problems. Saying that, it does suggest if you're writing your own value types, you're probably going to want to override most of object's base methods, particularly GetHashCode, which is used in quite a lot of places.

Tuesday, April 03, 2007

The number one internet resource for Metastorm crap

It's always interesting to look through the search terms that have led people here or to the other sites I have something to do with. It's certainly a great work avoidance tactic. So I was pleased to see that the term Metastorm crap had landed somebody here. Then when I did a search for Metastorm crap myself I was even more pleased to see I'm number one for that search term. So there you are, come here for all the Metastorm crap you could ever need...

In fact I've just done a search for Metastorm shit and I'm number one for that as well! I must point out at this point that although the words may have appeared on the same page, they didn't actually appear in the same context... OK, they do now, but I'm not implying anything, OK?