Sunday, May 03, 2009

Adding trace to ASHX files

This is almost certainly caused by me being an idiot, but I know there are other people out there who are idiots on occasion so I thought I’d post this. I’ve never used Trace.Write in ASP.NET before and the first place I needed to use it was in a generic handler ASHX page. I didn’t look too closely at what was required and assumed that I needed to use Trace.Write in System.Diagnostics. That was my first mistake. This doesn’t add any trace output to the trace.axd page (though it would be cool if it did since I could then add trace to my assemblies that would show up, perhaps adding a custom trace listener could fix this?).

So then I looked at the code for System.Web.UI.Page and realised it has a Trace property but a generic handler doesn’t have this property so I thought that I might be out of luck. Eventually I realised that the HttpContext passed into the ProcessRequest method has a Trace property so I could just use that for all my tracing needs. Problem solved.

Update: I’ve now realised it’s pretty easy to include trace output from System.Diagnostics.Trace calls in ASP.NET apps. Just add the following to web.config

<configuration>
  <system.diagnostics>
    <trace autoflush="false" indentsize="4">
      <listeners>
        <add name="WebPageTraceListener"
            type="System.Web.WebPageTraceListener, System.Web, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
      </listeners>
    </trace>
  </system.diagnostics>

Baltimore skyline

Baltimore skyline panorama

There’s an advert for Microsoft on currently that shows a kid taking some photos and with a few clicks stitching them together into a panorama. All thanks to the ease of use of Vista. So when I was in Baltimore this week I took some photographs to attempt to do the same thing. After all, if some kid can do it, I’m sure I should be able to. But when I fired up Windows Photo Gallery I was unable to find any options to make a panorama. So I fired up Windows Live Photo Gallery instead and that did have the option. In fact it was pretty damn simple to create a panorama, as you can see above.

But two things bother me. Why are Microsoft advertising Windows by showing the capabilities of an application that doesn’t ship with the operating system? And why are there two different photo gallery applications which seemingly do the same thing but are subtly different?

Saturday, May 02, 2009

A simple WinForms numeric edit control

There are plenty of controls out there that will allow only numeric entry but they may not meet your needs. If you don’t want the up/down buttons, the built-in NumericUpDown control won’t be of use and using one of those huge libraries just for their numeric control may be overkill. If that describes your position, this uber-simple control may fit the bill.

  public class NumberControl : TextBox
  {
    /// <summary>
    /// Creates a new <see cref="NumberControl"/> instance.
    /// </summary>
    public NumberControl()
    {
      TextAlign = HorizontalAlignment.Right;
    }

    /// <summary>
    /// Triggered when a key is pressed. Swallows all keys except for digits.
    /// </summary>
    protected override void OnKeyPress(KeyPressEventArgs e)
    {
      base.OnKeyPress(e);
      string decimalSeparator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
      if (e.KeyChar.ToString() == decimalSeparator)
      {
        if (Text.IndexOf(decimalSeparator) > -1)
          e.Handled = true;
      }
      else if (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar))
      {
        e.Handled = true;
      }
    }
  }

Wednesday, April 22, 2009

Adding Street View to web pages

Street View has been available for a while but it didn’t interest me too much until recently when it launched in the UK. Then I noticed it was available as a part of the Google Maps API so I decided I’d add it to the Random Pub Finder. I initially thought it would work like the user interface available on the Google Maps website, but it doesn’t seem such an integrated solution is possible. To be fair, dragging the little man around your map probably isn’t what you’ll want to do generally so this isn’t a big issue, and if you’re clever you could probably implement this kind of solution anyway. I was pleased to find it was very easy to add to the site. First add a div to your page that will contain the Flash control

  <div name="pano" id="pano" style="width: 750px; height: 300px">
    <div id="panoError" style="text-align: center; margin-top: 100px;color: #aaa;">Loading...</div>
  </div>

Then add  a reference to the Google Maps API script.

<script src="http://maps.google.com/maps?file=api&amp;v=2.x&amp;key=ABQIAAAAjtZCgAx5i04BiZDO6HlxhRSDF8NMhBf90dVWYNzYEfop4QQs3RSkYVE7vnmvtIBRRQjoFXq4kz15Mg" type="text/javascript"></script>

Finally add some JavaScript to initialise the control.

    function load()
    {
      var latLong = new GLatLng(51.412640159832, -0.30039334012124);
      var panoramaOptions = { latlng:latLong };
      var myPano = new GStreetviewPanorama(document.getElementById("pano"), panoramaOptions);
      GEvent.addListener(myPano, "error", handlePanoError);
    }

    function handlePanoError(errorCode)
    {
      var error = "An error occurred";
      if (errorCode == 600)
      {
        error = "No street view available";
      }
      else if (errorCode == 603)
      {
        error = "The Flash plugin is not available";
      }

      document.getElementById("panoError").innerText = error;
    }

Actually a lot of this JavaScript isn’t even needed, you can get away with just the first three lines of the load function, but the rest is useful for error handling. Error 600 can happen quite frequently so is best handled in some manner. I’ve not seen error 603 myself but I’ve shown it here because some of the code examples I’ve seen use the constant FLASH_UNAVAILABLE, which doesn’t seem to be defined anywhere, meaning when any error occurs you’ll actually get a script error if you use this constant. I guess there are more errors that can occur but I’ve not come across them yet.

Friday, April 10, 2009

Renaming a user in Metastorm BPM

Rename Metastorm user

People change their names for all sorts of reasons, marriage being the most common, but there are plenty of other reasons, such as a change of religious belief or wanting to get rid of an unfortunate surname. Whatever the reason, the Users and Roles utility that ships with Metastorm BPM doesn’t have any support for changing user names. The FreeFlow Administrator can help out here. Just fire it up, change the user’s name and apply the changes. This will change the user name in all relevant Metastorm tables. However it can’t change every reference to that user. For instance if you’ve stored a user name in a custom variable, that won’t get updated, since there isn’t really any way of knowing that the custom variable value refers to a user.

This can also be achieved programmatically. This may be useful if your corporate standards have changed and you need to change every user’s name in the system. Or you may want to prefix the users’ names with the domain name because you’re moving to SSO. Whatever the reason, here’s some sample code to achieve this.

using System;

using FreeFlow.Administration;

namespace ChangeAllUsers
{
  class Program
  {
    static void Main(string[] args)
    {
      Server server = new Server();
      server.Connect("sa", "a", "Metastorm");
      foreach (User user in server.Users)
      {
        Console.WriteLine("Processing " + user.Name);
        user.Name = "domain\\" + user.Name;
        user.ApplyChanges();
      }
    }
  }
}

Monday, April 06, 2009

Documenting Metastorm procedures

You may be aware of the procedure documenter produced by Process Mapping, the company I work for. If not, have a look. It’s a Designer add-in, which means a menu item is added to the Designer’s Tools menu that kicks off the documenter and generates the HTML documentation. I spent a little time today extracting the HTML generation code from the add-in assembly into a separate assembly. This means that the code can be called from anywhere you like, which leads to the possibility of automating your documentation generation. Combine this with FreeFlow and you can automate the documentation of all your published procedures. The following console application demonstrates how this could be achieved.

using System;
using FreeFlow.Administration;
using ProcessMapping.ProcedureDocumentationGenerator;

namespace DocumentProcedures
{
  class Program
  {
    static void Main(string[] args)
    {
      Server server = new Server();
      server.Connect("sa", "a", "Metastorm");
      foreach (Procedure proc in server.Procedures)
      {
        Console.WriteLine("Processing " + proc.Name);

        string filename = "c:\\temp\\" + proc.Name + ".xep";
        proc.Versions.LatestVersion.SaveToFile(filename);

        string htmlFilename = "c:\\temp\\html\\" + proc.Name + ".html";
        DocumentationGenerator generator = new DocumentationGenerator();
        generator.IncludeMapImages = true;
        generator.Generate(filename, htmlFilename);
      }
    }
  }
}

I believe later versions of SQL Server allow the execution of .NET code from within the database, so I would imagine it is possible to add a trigger to the eProcedure table that kicks off this code whenever a new record is added, so documentation will always be up to date.

Of course the procedure documenter isn’t a silver bullet. To generate useful documentation, some work will be required to ensure the notes in you procedures contain useful information.

Friday, April 03, 2009

Debugging server-side scripts in Metastorm BPM

Script Debugging in Metastorm BPM

Debugging server-side scripts in the Metastorm BPM can be difficult. One thing that can help with debugging JScript/VBscript scripts is the FreeFlow Administrator. When an error occurs in your script, generally you’ll be given a line number where the error occurred. This may not relate to a line number in the Designer because scripts are merged together when they get published to the database. The FreeFlow Administrator provides a simple way to view your scripts and see the line numbers and hence track down bugs more easily.

Unfortunately in the world of JScript.NET, when an error occurs you won’t get a line number telling you where it happened. If you want to learn more about debugging .NET code in Metastorm BPM, I would recommend Process Mapping’s .NET course (generally presented by myself).

Tuesday, March 31, 2009

Saving latest versions of procedures from a Metastorm BPM database

Save Metastorm Procedures

One thing that comes up quite often is how to get all the latest procedures from a Metastorm database. The FreeFlow Administrator makes this easy. Simply load it up, connect to the database and use the ‘Save procedures…’ action. Select the folder to save the procedures to and everything will be saved there, included all libraries.

Like everything else in the FreeFlow Administrator, this can all be achieved programmatically, with something like the following.

      Server server = new Server();
      server.Connect("sa", "a", "Metastorm75");
      server.RetrieveLatestProcedures("c:\\temp");

Why would you want to do this? Perhaps you regularly want to get all the latest versions of the procedures in your Metastorm database before you head out of the office and want a script/console app that does this for you.

Finally, you can also get the latest versions of a specific procedure, using something like this

      server.Procedures["Flight"].Versions.LatestVersion.SaveToFile("c:\\temp\\flight.xep");

Saturday, March 28, 2009

XSLT to generate an HTML listing of your iTunes library

The data for the music in an iTunes library is stored in an XML file which means that it should be simple to produce an XSLT file to generate an HTML document listing all the albums in your iTunes library. Well, it would be, but the XML format used by iTunes is, how can I put this, idiosyncratic. Other people may use more fragrant language to describe it…

Anyway I found this very useful article describing how to create an XSLT file to do almost what I wanted, but I wasn’t interested in grouping by genre, since the genre data is often not very accurate or helpful. I’m also a little anal about my music collection and wanted it sorted by artist name, rather than album name. This part was slightly tricky because the data may not be complete. The album artist field is often not entered and the artist field may not be the album artist, even when the album is not a compilation. And finally the compilation flag may be set when you don’t expect it to be or conversely not set when you expect it to be. e.g. a greatest hits album may be flagged as a compilation. This is arguably correct, but I wanted these kind of albums to be grouped with the artist. So quite a few changes were required which is why I’m posting this, it’s not just me trying to get some reflected glory (and hence me linking to the original article repeatedly)

Anyway, the basic idea is the same as the original article. First put an XML file in the same directory as your iTunes library, as follows

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="albumList.xsl" type="text/xsl"?>
<wrapper>
  <incl file="iTunes Music Library.xml"/>
</wrapper>

Next is the XSLT, in a file called albumList.xsl in the same directory, which looks like this.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="html" encoding="UTF-8" indent="yes"/>

  <!-- match the wrapper and apply templates to the <incl> xml file -->
  <xsl:template match="/wrapper">
    <xsl:apply-templates select="document(incl/@file)/plist/dict/dict"/>
  </xsl:template>
  
  <xsl:key name="songsByAlbum" match="dict" use="string[preceding-sibling::key[1]='Album']"/>

  <xsl:template match="dict">
    <html>
      <head>
        <title>iTunes Album Listing</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <style>
          body
          {
            font-family:Arial;
          }
        </style>
      </head>
      <body>
        <table>
          <thead>
            <tr>
              <td><b>Artist</b></td>
              <td><b>Album</b></td>
            </tr>
          </thead>
          <xsl:variable name="song" select="/plist/dict/dict/dict"/>

          <!-- output the albums that aren't compilations -->
          <xsl:for-each select="$song[generate-id(.)=
        generate-id(key('songsByAlbum',string[preceding-sibling::key[1]='Album'])[1])]">
            <xsl:sort select="concat(string[preceding-sibling::key[1]='Album Artist'], string[preceding-sibling::key[1]='Artist'])"/>

            <xsl:for-each select="key('songsByAlbum',string[preceding-sibling::key[1]='Album'])
          [not(true[preceding-sibling::key[1]='Disabled'])]
          [not(true[preceding-sibling::key[1]='Compilation'])]            
          [1]">
              <xsl:call-template name="outputAlbum" />
            </xsl:for-each>
          </xsl:for-each>

          <!-- output each compilation -->
          <xsl:for-each select="$song[generate-id(.)=
        generate-id(key('songsByAlbum',string[preceding-sibling::key[1]='Album'])[1])]">
            <xsl:sort select="string[preceding-sibling::key[1]='Album']"/>

            <xsl:for-each select="key('songsByAlbum',string[preceding-sibling::key[1]='Album'])
          [not(true[preceding-sibling::key[1]='Disabled'])]
          [true[preceding-sibling::key[1]='Compilation']]
          [not(string[preceding-sibling::key[1]='Album Artist'])]
          [1]">
              <xsl:call-template name="outputAlbum" />
            </xsl:for-each>
          </xsl:for-each>
        </table>
      </body>
    </html>
  </xsl:template>

  <xsl:template name="outputAlbum">
    <tr valign='top'>
      <!-- the artist: -->
      <td>
        <xsl:choose>
          <xsl:when test="string[preceding-sibling::key[1]='Album Artist']">
            <xsl:value-of select="string[preceding-sibling::key[1]='Album Artist']"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:choose>
              <xsl:when test="true[preceding-sibling::key[1]='Compilation']">
                <i>Compilation</i>
              </xsl:when>
              <xsl:otherwise>
                <xsl:value-of select="string[preceding-sibling::key[1]='Artist']"/>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:otherwise>
        </xsl:choose>
      </td>
      <!-- the album name: -->
      <td>
        <xsl:value-of select="string[preceding-sibling::key[1]='Album']"/>
      </td>
    </tr>
  </xsl:template>
  
</xsl:stylesheet>

Now open the XML file in your favoured browser (as long as your favoured browser is IE or FireFox) and the HTML should be generated. It can be slow, it might be the XSLT can be optimised somewhat but I’m not hugely experienced in optimising XSLT so haven’t investigated further. And of course the XSLT can’t cope with all rubbish data in your iTunes library, garbage in, garbage out.

One other improvement would be to improve the sorting so that artists such as The Fall came under F, rather than T, but I have no idea how to achieve that.

Tuesday, March 24, 2009

Saving all folder attachments from a Metastorm database

A question came up on the Metastorm BPM forums about saving all folder attachments from a Metastorm database. Folder data is saved in a particularly strange format so this wouldn’t be very straightforward but with the FreeFlow .NET library things are much simpler. I thought I’d post it here just to show how easy it is. In fact I may start posting some more simple FreeFlow examples here, rather than posting them as downloads on the FreeFlow site, because it’s much easier than fiddling with ASP.NET pages.

It’s a console application that should work with .NET 2 upwards.

using System;

using FreeFlow.Administration;

namespace GetAllAttachments
{
  class Program
  {
    static void Main(string[] args)
    {
      Server server = new Server();
      server.Connect("sa", "a", "Metastorm75");
      foreach (Map map in server.Maps)
      {
        foreach (Folder folder in map.Folders)
        {
          foreach (Attachment attachment in folder.Attachments)
          {
            string fileName = "C:\\temp\\" + folder.FolderId + attachment.FileName;
            Console.WriteLine("Processing " + fileName);
            attachment.SaveToFile(fileName);
          }
        }
      }
    }
  }
}

Sunday, March 22, 2009

When will Delphi die?

I have a theory. As with all my theories, it probably doesn’t stand up to close scrutiny but I’ll put it out there none the less. And this is it. The more trouble a company is in, the more marketing emails they will send out. and if they are in really big trouble, then they start phoning people. 

If this theory is in any way correct then Embarcadero (purchasers of Delphi) are in big trouble, or their Delphi division is at least. Not only do I constantly receive emails from them or their partners telling me how great the new version of Delphi is, but I’ve also had at least three phone calls from people desperate to sell me Delphi licenses. Unfortunately I have no interest in buying Delphi licenses, since I haven’t touched Delphi code for years. Ten years ago Delphi was a great product, it beat Visual Studio hands down for its power to create Windows apps. But along came .NET, which in its original incarnation was fairly decent and has been getting better and better as time goes on. Now Delphi is essentially an irrelevance, except for people needing to maintain an existing code base. Who in their right mind would choose Delphi to build a new product? At this point I was going to direct you to the JobStats page showing demand for Delphi skills in the UK but they don’t even bother to list it anymore. There may be a small niche area where native compilation is required for performance reasons and Delphi may fit the bill, but I suspect this niche is getting smaller and smaller. Another problem that Embarcadero have is that it is almost impossible to make money from development tools. Microsoft essentially provide their tools as a loss leader and also provide damn good free versions. There are also lots of other good free development tools out there, so why pay for a development tool at all, particularly one for an obscure language that is no longer cool and happening? To be fair, you can pick up a fairly decent version of Delphi for free.

So the only question I have is when will Delphi die? I guess, like Cobol and FoxPro and a hundred other seemingly redundant technologies, it will continue to trudge along for a long time yet. Or perhaps I’m completely wrong and there is some place where Delphi can still be a winning technology, but I can’t think of one myself.

Saturday, March 21, 2009

Error logging in ASP.NET using a HTTP module

I wrote many moons ago about logging errors from an ASP.NET website but even then I knew there was a better way of doing it. The problem with that implementation was that it assumed the ASP.NET application was under my control. What happens if you want to add error logging to somebody’s else application for which you don’t have the source? Or what about an application you’ve written yourself that you’re selling to other people but also using internally, and you don’t want to prescribe to your customers how they should implement their logging? What is required is a more flexible approach to logging, something that can be plugged into any ASP.NET application.

Fortunately ASP.NET provides such a mechanism, via HTTP modules. Another reason I’d never looked at implementing logging this way was that I thought it might be tricky to do, but in fact it is so simple it took me all of an hour to produce a working solution.

The first thing to do is create a new class library and add a class that implements the IHttpModule interface. This interface has only two methods, Init and Dispose. Here's how I implemented it.

  public class ErrorLogger : IHttpModule
  {
    public void Init(HttpApplication context)
    {
      context.Error += new EventHandler(context_Error);
    }

    public void Dispose()
    {
    }

    private void context_Error(object sender, EventArgs e)
    {
      Exception ex = HttpContext.Current.Server.GetLastError();
      // log the exception however you like
    }
  }

Pretty simple. The logging code isn’t shown for brevity’s sake but all the class does is hook up an event handler for the Error event and within that event handler do whatever is necessary to log the error. In our case, we email the error and put it in a database table, but you can log it however you wish. (here’s some exception logging code for you)

Now all that’s required is to drop the assembly in the app’s bin directory and tell the ASP.NET application about the HTTP module. This is done via the web.config file with the following in the <system.web> section

  <httpModules>
    <add type="Utilities.ErrorLogger" name="ErrorLoggingModule"/>
  </httpModules>

type is the .NET type and name is whatever you like. And, er, that’s it.

As you’ve probably realised HTTP modules are powerful little things that can be used to do all kinds of stuff in a flexible manner.

Update – for those not reading the comments, there’s a free logging tool called ELMAH that can do all this for you without needing to write any code.

Thursday, March 19, 2009

IE8’s compatibility view is not IE7

It would appear that IE8 has been released today which coincides with me finding out something unpleasant about its compatibility view. I’d assumed switching to compatibility view would show the web page using IE7’s rendering engine. But this doesn’t seem to be the case. Go to the Process Mapping website and try out the dropdown menus. When you move outside the boundaries of a menu it should disappear, as you’d expect. Using IE6, IE7, IE8 (native mode), FireFox, Safari and Chrome that’s exactly what happens. But in IE8’s compatibility view the menu stays where it is.

So I can only assume compatibility view is not IE7 in new clothing. Given that anybody can switch to compatibility view for whatever reason and returning to that site will stick with that setting, this means that the introduction of IE8 means rather than having one other browser to test against, we have two instead! Oh great…

Tuesday, March 17, 2009

Whatever happened to NDoc?

NDoc was one of my favourite tools for .NET. Document your assemblies with the .NET XML documentation tags, point NDoc at them and out comes a help file. It was simple to use but was also powerful enough to customize the output in most ways you’d want.

Go to the linked website and you’ll see not much has happened on the NDoc project since 2005. Unfortunately support for .NET 2 was never completed before the original author decided to give up on the project and it looks like nobody has picked up the baton to develop it further. This is understandable to an extent. After all Microsoft have come out with Sandcastle which essentially does the same thing as NDoc. But Sandcastle is difficult to love. It has no user interface and builds take forever compared to NDoc.

The user interface problem can be solved by using Sandcastle Help File Builder, which does a nice job of looking like NDoc, but is still hampered by the underlying Sandcastle technology. After much frigging around I’m still unable to figure out how to add custom HTML into my documentation (for Google Analytics and the like) on a per project basis. I can do it globally by messing with the templates but this means I have to modify the templates for each build of a particular project, which is not ideal.

Perhaps I’m missing something, but it seems sad that 4 years since development on NDoc stopped, we still don’t have something as easy to use or as fast, even with the might of Microsoft behind it. I’m not surprised the original author decided to stop working on it, apparently he was getting threatened because his support for .NET 2 wasn’t coming along fast enough… And I’m sure the thought of trying to compete with Microsoft didn’t encourage his efforts either. But Microsoft have failed to deliver IMHO so I’m still missing NDoc after all this time.

Monday, March 16, 2009

US states table for SQL Server

I couldn’t find any SQL to generate a table of US states for SQL Server though I found this for MySql, so I modified it slightly and came up with this for SQL Server. Create the table with this

CREATE TABLE States(
    StateCode char(2) NOT NULL,
    StateName varchar(250) NOT NULL,
 CONSTRAINT PK_States PRIMARY KEY CLUSTERED 
 (
    StateCode ASC
 )
)

And populate it with this

insert into States values ('AL', 'Alabama');
insert into States values ('AK', 'Alaska');
insert into States values ('AZ', 'Arizona');
insert into States values ('AR', 'Arkansas');
insert into States values ('CA', 'California');
insert into States values ('CO', 'Colorado');
insert into States values ('CT', 'Connecticut');
insert into States values ('DE', 'Delaware');
insert into States values ('DC', 'District of Columbia');
insert into States values ('FL', 'Florida');
insert into States values ('GA', 'Georgia');
insert into States values ('HI', 'Hawaii');
insert into States values ('ID', 'Idaho');
insert into States values ('IL', 'Illinois');
insert into States values ('IN', 'Indiana');
insert into States values ('IA', 'Iowa');
insert into States values ('KS', 'Kansas');
insert into States values ('KY', 'Kentucky');
insert into States values ('LA', 'Louisiana');
insert into States values ('ME', 'Maine');
insert into States values ('MD', 'Maryland');
insert into States values ('MA', 'Massachusetts');
insert into States values ('MI', 'Michigan');
insert into States values ('MN', 'Minnesota');
insert into States values ('MS', 'Mississippi');
insert into States values ('MO', 'Missouri');
insert into States values ('MT', 'Montana');
insert into States values ('NE', 'Nebraska');
insert into States values ('NV', 'Nevada');
insert into States values ('NH', 'New Hampshire');
insert into States values ('NJ', 'New Jersey');
insert into States values ('NM', 'New Mexico');
insert into States values ('NY', 'New York');
insert into States values ('NC', 'North Carolina');
insert into States values ('ND', 'North Dakota');
insert into States values ('OH', 'Ohio');
insert into States values ('OK', 'Oklahoma');
insert into States values ('OR', 'Oregon');
insert into States values ('PA', 'Pennsylvania');
insert into States values ('RI', 'Rhode Island');
insert into States values ('SC', 'South Carolina');
insert into States values ('SD', 'South Dakota');
insert into States values ('TN', 'Tennessee');
insert into States values ('TX', 'Texas');
insert into States values ('UT', 'Utah');
insert into States values ('VT', 'Vermont');
insert into States values ('VA', 'Virginia');
insert into States values ('WA', 'Washington');
insert into States values ('WV', 'West Virginia');
insert into States values ('WI', 'Wisconsin');
insert into States values ('WY', 'Wyoming');

Friday, March 06, 2009

WPF ASCII grid part 3

It’s been a while since I last posted about my efforts to write a simple WPF app. At the end of my last post I had managed to create a custom control to display my ASCII grid and things were coming along nicely. The next thing I wanted to was pretty straightforward, or so I thought… I wanted to add a property to my control that decides whether the grid shows the standard ASCII values or the extended ASCII range. To do this I thought the simplest thing to do, when the property value changed, was clear out my grid and re-add the cells with the new values. Maybe not the most efficient approach but it seemed like the simplest option since there doesn’t seem a way to access the cell contents of a grid to change the text values.

But the problem with this approach is it doesn’t really work. Changing the property value calls the code but afterwards all that can be seen is the grid lines, not the new contents of the cells. Resizing the window does show the new cell contents so I assumed this was a refresh issue. Looking in to how to refresh a WPF control came up with these possible options

  • Call Dispatcher.Invoke with a priority of DispatcherPriority.Render
  • Call InvalidateVisual
  • Call InvalidateMeasure
  • Call InvalidateArrange
  • Call Measure
  • Call OnChildDesiredSizeChanged

I’ve no idea which of these I should be calling but I tried all of them and none had any effect. So I am at something of a loss. I think the next step is to rework my code so I don’t recreate the TextBlocks I’m using to display the ASCII values and just update the Text property of the existing TextBlocks instead.

Tuesday, March 03, 2009

FEEDJIT

If you look further down this page, you’ll see a map of the world covered with what looks like the pox. Click on the map and you’ll be whisked off to the Feedjit site which shows the location of recent hits to this site and which pages were visited. I guess it isn’t really providing any more information than I can get from Google Analytics but I think it is displayed in a much more intuitive way. Are you listening Google?

Google AJAX APIs Playground

Mostly as a reminder to myself, Google have added a AJAX APIs Playground page that shows off some of the many features they provide in Google Maps, Local Search etc. There’s lots of things there that I had no idea about and you can edit the code in place to play around with the features. Sweet.

Friday, February 27, 2009

Copying a stream to another stream

It’s obvious that the ability to copy the contents of one stream to another is something that you’re likely to want to do fairly regularly. I vaguely recall that this will be added to some version of the .NET Framework but until that time, here’s a simple implementation that should do the trick. It could easily be converted into an extension method so it plays better in the .NET 3 world.

    /// <summary>
    /// Copies a stream to another stream
    /// </summary>
    /// <param name="copyFrom">The stream to copy from</param>
    /// <param name="copyTo">The stream to copy to</param>
    public static void CopyTo(Stream copyFrom, Stream copyTo)
    {
      const int buffSize = 128;
      byte[] buff = new byte[buffSize];
      int count;
      do
      {
        count = copyFrom.Read(buff, 0, buffSize);
        copyTo.Write(buff, 0, count);
      }
      while (count > 0);
    }

Tuesday, February 24, 2009

Spotify – the future of music?

I’ve just discovered Spotify (via Tim Anderson) and so far I’m thoroughly impressed. Previous implementations of this kind of thing (last.fm, Pandora) have restricted your choices of what you can listen to, making them feel more like listening to a radio station than listening to your own music collection. But Spotify lets you choose exactly what you want to listen to from its database. It doesn’t have every song by every artist, like most online music sources there’s no Beatles (obviously Jacko doesn’t need the extra cash, which doesn’t quite match with what I’d heard), some of my obscure musical preferences are missing (no Godspeed You Black Emperor) and even the artists they do have aren’t generally complete. But that’s a minor quibble, there’s a still a huge range of music available.

Streaming is super quick and the ads are currently pretty infrequent and unobtrusive. The bandwidth requirements seem pretty minimal too, I could happily work in a Remote Desktop session whilst listening and I didn’t notice any dropouts.

So is this the future of music listening? I certainly hope so. The big question is whether their business model works. Will the ads cover costs? Will the music companies suddenly get cold feet like they did with Pandora in the UK? Will their servers continue to be so snappy when they become super popular? If the ads become too frequent or in your face, listening might become painful. OK, you can get rid of the ads by paying $9.99 a month but if I was to pay for any online music service I’d want to have the physical bits (with no DRM) so I’d be sure I can still listen to them if the company folded.

The only thing I’d really like to see is the integration of the online stuff with my own music library. So if I want to listen to my own ripped music I can from the same player, rather than having to jump out to iTunes. But in the mean time, I’ve got a lot of new (to me) music to listen to.

Sunday, February 22, 2009

BPM for business users

Prototype activity From my time on the Metastorm forums one thing is obvious, most people implementing Metastorm solutions are not business people. Mostly they are technical people, with a few not so technical people. And it’s generally the not so technical people who are having the biggest problems getting to grips with the product. Is that a failing of the software? I’d say not, although it could arguably be a failing of the marketing of the software, which like most BPM products suggests a non technical person can use it from start to finish to produce a working system.

This situation reminds me of other areas of software development, like the development of websites, or application development. A while ago, people thought anyone with a copy of FrontPage could develop their own website or anyone with a copy of VB could knock together a working application. But these other areas have matured enough to recognise that actually those pesky developers are still required (or to put it another way, designers can’t code and coders can’t design) and the development environments are now set up in such a way that the designers can work with the coders to produce a working system. For a website, the designer can produce a HTML layout that looks good and then the coder can add the required code so it does something. In the world of Windows development we are moving to WPF and other technologies where the layout is separated from the code, so the designer can produce the pretty screens and the coder can then add code to do stuff without both sides stepping on each others toes too much.

And for me, that’s the approach that BPM will have to take at some point, realising that the business people can’t code and the coders don’t understand the business, so trying to put only one of these people in charge of the BPM system will never fly. I think Windows Workflow is a step in the right direction with its ability to create custom activities. The coder can create all the required custom activities and then the business person can plug these together like Lego as required. Or this could work in the opposite direction, where the business user produces their process and adds dummy activities where they need functionality to be implemented and the coder goes off and creates the required activities.

With that in mind, I created a simple PrototypeActivity that can be added to a workflow and lets the user specify the inputs and outputs that will be need to be implemented. The screenshot shows how it looks in operation (although a proper implementation would probably provide a better user interface). The code is below.

  public enum PropertyDirection
  {
    In,
    Out,
    InOut
  }

  public class ActivityProperty
  {
    private string propertyName = "";
    public string PropertyName
    {
      get { return propertyName; }
      set { propertyName = value; }
    }

    private string description;
    public string Description
    {
      get { return description; }
      set { description = value; }
    }

    private PropertyDirection direction;
    public PropertyDirection Direction
    {
      get { return direction; }
      set { direction = value; }
    }

    public override string ToString()
    {
      return direction.ToString() + " - " + propertyName.ToString();
    }
  }

  public class PrototypeActivity: Activity
  {
    public static DependencyProperty PropertiesProperty =
      DependencyProperty.Register("Properties", typeof(ActivityProperty[]), typeof(PrototypeActivity));

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    [Browsable(true)]
    [Description("The properties the activity requires")]
    public ActivityProperty[] Properties
    {
      get
      {
        return ((ActivityProperty[])(base.GetValue(PrototypeActivity.PropertiesProperty)));
      }
      set
      {
        base.SetValue(PrototypeActivity.PropertiesProperty, value);
      }
    }
  }

Friday, February 20, 2009

Rude Swiss

Condom shop in BaselContinuing with the rude theme, here’s a photo from my not so recent trip to Basel in Switzerland. We may assume it’s the Dutch who have the monopoly on lewd behaviour and the Swiss are more interested in banking, cuckoo clocks and chocolate. But perhaps the racial stereotypes are incorrect, here’s a shop devoted to selling condoms. I’m probably showing off my ignorance, but how can you have a shop that only sells condoms? Are there enough varieties to fill it? I didn’t enter to find out the answer.

Friday, February 13, 2009

Rude snowman

Rude snowman

Perhaps it’s just my dirty mind, but the snowman that Jo and Lola made the other day ended up looking less like a man and more like, well something else entirely. The huge erection has now melted away…

Monday, February 09, 2009

Not getting album artwork from iTunes

I had a thought the other day, how does iTunes get its album artwork? I guessed it was some kind of web service so fired up Fiddler to see if anything was getting thrown around. And sure enough iTunes was throwing a HTTP request to some server, that looked something like this (this is somewhat simplified since you can also pass CDDB information which presumably increases the chances of getting a correct hit).

http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa?an=Cult&pn=Love

Put that in your browser and you’ll see an XML document is returned. It’s in Apple’s favoured XML format and it looks like there is a URL in there that can be used to retrieve the album artwork. Unfortunately, plugging that URL into your browser won’t return the image… At this point I kind of lost interest because I didn’t actually have any use for getting hold of album artwork (unless I wanted to automate the process for iTunes but I’m not that anal about getting artwork). But I did have a bit of a look round the web and found these two articles on doing the same thing. And it would appear Apple are pretty keen on people not downloading artwork via their own code. Dunnow why, copyright issues I guess, but it looks like even if it is possible to hack the system, Apple will change the way it works to stop your code working.

If you do want to download artwork, I suspect Amazon Web Services is going to be a better approach.

Saturday, February 07, 2009

How to confuse IE with a 302 redirect

It’s very simple, create a PHP pages called test.php, the contents of which are

<?php
  header("Location: test.php");
  exit;
?>

Now point IE8 (probably earlier versions of IE as well I’d guess) at the page and watch as it tries in vain to fetch the page. It eventually times out, after trying to fetch the same page over 1000 times (take a look with Fiddler to see the problem). FireFox and Chrome are much more sensible in this scenario and give up quite soon. As the dumb developer who caused this problem, it took me quite some time to figure out my redirect wasn’t working rather than the website being very ill

WPF ASCII grid part 2

This is the second in a series where I try to learn how to develop WPF apps. The first part is here.

So my next step was to put all the ASCII grid code into a custom control. My first attempt was to inherit from Grid and add the logic to create the cells in the inherited class. The problem with this approach was that the grid’s row and column definitions could be edited in Visual Studio which I didn’t want. So I decided to inherit from Panel and add the grid as a child control. When I did that, running the application showed up nothing at all. I finally realised that was the wrong approach, since the Panel class is designed to allow the end user to add their own child controls. I guess the WPF runtime is looking at the XAML to see which children should be added to the panel and there aren’t any. So finally I inherited from Control and then had to figure out how to add the grid as a child. Control doesn’t have a Children property so it’s not obvious how to add your own child controls. But it turns out it’s pretty easy to do. You just have to override VisualChildrenCount and GetVisualChild as shown below.

  public class AsciiGrid : Control
  {
    static AsciiGrid()
    {
      DefaultStyleKeyProperty.OverrideMetadata(typeof(AsciiGrid), new FrameworkPropertyMetadata(typeof(AsciiGrid)));
    }

    private Grid grid;
    public AsciiGrid() : base()
    {
      grid = new Grid();

      const int width = 16;
      const int height = 16;
      for (int x = 0; x < width; x++)
      {
        grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star), });
      }
      for (int y = 0; y < height; y++)
      {
        grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Star), });
      }
      for (int x = 0; x < width; x++)
      {
        for (int y = 0; y < height / 2; y++)
        {
          int asciiValue = ((y * width) + (x + 1));

          // number
          TextBlock rect = new TextBlock();
          rect.Text = asciiValue.ToString();
          rect.SetValue(Grid.RowProperty, y * 2);
          rect.SetValue(Grid.ColumnProperty, x);
          grid.Children.Add(rect);

          // ASCII value
          rect = new TextBlock();
          rect.Text = Convert.ToChar(asciiValue).ToString();
          rect.SetValue(Grid.RowProperty, (y * 2) + 1);
          rect.SetValue(Grid.ColumnProperty, x);
          grid.Children.Add(rect);
        }
      }
    }

    protected override int VisualChildrenCount
    {
      get
      {
        return 1;
      }
    }

    protected override Visual GetVisualChild(int index)
    {
      return grid;
    }
  }
So I now have a standalone control in my application. The application looks exactly as it did before but I’ve now got an exceedingly useful re-usable ASCII grid control. OK, maybe not so useful, but this is a learning experience, so cut me some slack. The only thing to note is the changes required to the XAML to host the control, which looks like this.
<Window x:Class="Ascii.AsciiWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Ascii="clr-namespace:Ascii"    
    Title="Ascii" Height="370" Width="413" Loaded="Window_Loaded">
    <Ascii:AsciiGrid x:Name="m_Grid">
    </Ascii:AsciiGrid>
</Window>

WPF ASCII grid part 1

Ascii

I thought it was about time I learned about WPF so thought I’d start with a very simple application, a grid showing the ASCII characters. It’s kind of pointless at the moment since you can find this information on the web pretty easily but I think I can make it somewhat more powerful and in the process learn more about WPF. This is what I’d like to add in the future and will hopefully blog about as I implement them

          • Turn the grid into a control
          • Show the extended ASCII characters
          • Make it look much sexier
          • Let the user choose the font
          • Let the user change the code page

The code currently looks like this. It’s all pretty straighforward. The first thing to note is the GridUnitType.Star enumerated value which means each column and row will be spaced equally in the window.

The other thing to note is the weird way the text blocks are assigned to the correct cells of the grid. It doesn’t seem a natural way to do it, but I guess once you know that’s how it’s done, it’s pretty straightforward.

    public AsciiWindow()
    {
      InitializeComponent();
      BindGrid();
    }

    private void BindGrid() 
    { 
      const int width = 16;
      const int height = 16;
      for (int x = 0; x < width; x++) 
      { 
        m_Grid.ColumnDefinitions.Add(new ColumnDefinition() 
        { Width = new GridLength(1, GridUnitType.Star), }); 
      }
      for (int y = 0; y < height; y++) 
      { m_Grid.RowDefinitions.Add(new RowDefinition() 
        { Height = new GridLength(1, GridUnitType.Star), }); 
      }
      for (int x = 0; x < width; x++) 
      {
        for (int y = 0; y < height/2; y++) 
        {  
          int asciiValue = ((y*width)+(x+1));

          // number
          TextBlock rect = new TextBlock();
          rect.Text = asciiValue.ToString();
          rect.SetValue(Grid.RowProperty, y*2); 
          rect.SetValue(Grid.ColumnProperty, x); 
          m_Grid.Children.Add(rect); 

          // ASCII value
          rect = new TextBlock();
          rect.Text = Convert.ToChar(asciiValue).ToString();
          rect.SetValue(Grid.RowProperty, (y * 2)+1);
          rect.SetValue(Grid.ColumnProperty, x);
          m_Grid.Children.Add(rect); 
        } 
      } 
    }

Read part 2

Wednesday, February 04, 2009

Bugs = complexity

Many moons ago I discovered a bug in some software I use on a fairly regular basis (I won’t tell you which software since it isn’t relevant to the story and I don’t want this to appear to be a critique of the company or their development process, though you can probably figure out who it is if you look round the rest of this site). The application allows you to write server scripts in JScript.NET. It also does some validation of these scripts but in certain circumstances this validation incorrectly flags up problems with scripts that aren’t actually problems. It was a fairly innocuous bug so I reported it but didn’t push for it to be fixed.

Fast forward a year or so and a new version of the software comes out with a new feature that validates your scripts when you try to deploy a project to the server. Generally a useful feature except the previous bug is still there. Meaning I now can’t deploy perfectly valid projects due to the interaction of the previous bug with this new feature. So a minor unfixed bug has blown up into a major issue.

Which got me thinking. The kind of bugs that don’t get fixed are these kind of things. They only occur in particular rare scenarios. If they happened all the time, the chances are they would get fixed, if they are serious enough. But they do add complexity to the product and testing. No longer can we assume doing A will cause B to happen. Most of the time it will be true but occasionally doing A will cause C to happen. So any testing of new features will have to take this into account. In fact, testing of any new feature will have to take into account any unfixed bugs that may impact the new functionality.

There are many reasons for trying to fix as many bugs as possible (keeping customers happy, trying to fight the constant entropy inherent in software development), may I add this to the list? 

Tuesday, February 03, 2009

Backups

My backup strategy over the last few years has been pretty lame. Every month, Outlook reminds me I should do a backup of my source and I burn a CD. This kind of worked for a while but I’ve been getting more and more nervous about it. Am I sure I’m backing up everything I need to? Most of my email is stored on the web in GMail but there’s heaps of other things on my PC that may be vital but I just haven’t realised it yet. Not only that, but I was getting to the stage where a single CD wasn’t enough and the time taken to burn even that single CD was starting to bore me.

So today when I popped into Maplin for a USB cable I thought I’d have a look at the external hard drives. The Toshiba Stor E looked like the best bang for buck, 500GB for £65. So far I’m impressed. It looks pretty robust, with an aluminium case and no pointless bling. Installation was exceedingly straightforward. Plug it in and Vista recognised it immediately. Then simply configure Vista to do an automatic backup every week and that’s it.

Admittedly my first backup is currently happening and it’s not super fast, but I guess that will improve once it’s done the first full backup. Once it’s finished I’ll have to check that it’s actually backed up everything I want it to, since the backup utility is pretty vague about what it’s going to do. And then I’ll have to think about taking my backup offsite, which for me means carrying the drive into the house. If my shed and house burn down, I’ll have bigger worries than having a decent backup. 

Sunday, February 01, 2009

Dan le Sac vs Scroobius Pip "Thou Shalt always Kill"

I just love this. It’s funny, has a great beat and what a beard!

One of the problems with working from home

However much it snows this evening, I can’t call the office in the morning claiming the weather is too bad for me to get to work.

Friday, January 23, 2009

A simple plug-in framework for .NET apps

If you want to add plug-in support to your application then you might start looking at Microsoft’s Managed Extensibility Framework or System.Addin. Whilst I have no experience of these frameworks, when I looked at them I decided they were just too complicated for my needs. Also I was targeting .NET 1.1 so couldn’t use either of them. All I wanted to be able to do was to write a class that implements a particular interface (for importing files from one of a number of external file formats), dump it in the application’s directory and for the application to recognise the assembly and add the supported file type to its list of available file types. I won’t bore you with the details of the interface, since it’s obviously specific to the application being developed, but here’s the code for loading the assemblies and creating instances of the available importers.

      // load all importers
      string applicationDirectory = System.IO.Path.GetDirectoryName(
        Assembly.GetExecutingAssembly().Location);
      DirectoryInfo info = new DirectoryInfo(applicationDirectory);
      FileInfo[] files = info.GetFiles();
      List<Type> types = new List<Type>();
      for (int i = 0; i < files.Length; i++)
      {
        // load assemblies and see what is in there
        if (files[i].Extension.ToLower() == ".dll")
        {
          Assembly thisAssembly = Assembly.LoadFrom(files[i].FullName);
          Type[] assemblyTypes = thisAssembly.GetTypes();
          for (int j = 0; j < assemblyTypes.Length; j++)
          {
            if (assemblyTypes[j].GetInterface("IImport") != null)
            {
              ConstructorInfo wfConstructor = assemblyTypes[j].GetConstructor(Type.EmptyTypes);
              object obj = wfConstructor.Invoke(null);
              IImport importer = (IImport)obj;

              importers.Add(importer);
            }
          }
        }
      }

This worked well for me. I’m sure it wouldn’t work in all scenarios and MEF/System.Addin may be more appropriate to more complex scenarios (if you are worried about versioning or running your add-in in a sandbox for instance) but it’s a quick and dirty method for implementing plug-ins.

Thursday, January 22, 2009

Turn on script debugging!

The other day I was pointed in the direction of a new website for a company I know. The owner was very pleased with the work a web design agency had done for him. Unfortunately the first thing I saw was a script error, then another then finally the page appeared. Pretty nice it was too, but the whole experience was somewhat spoiled by those script errors. Of course most people have script debugging turned off so they don’t see these errors but if you’re paying someone to develop your website it is something you need to do.

I wouldn’t recommend having it turned on all the time, the fact is the web is almost unusable if you do have script debugging enabled. Some websites cause so many errors that the only solution is to kill your browser and a large number of high profile websites have some kind of script error. Of course, some would say this is only an IE problem and point to the crappy way IE implements the debugger notification in a modal dialog box and that is certainly true. Perhaps it was done that way so that it is so in your face, that if you’re the developer of the site you just have to do something about it. I think the actual consequence is that anybody who has turned it on turns it off at the earliest opportunity.

But I digress, the point is if you’ve paid somebody to develop your website, make sure they’ve actually done a decent job, even if the only people who’ll notice they haven’t are anal geeks like me.