Skip to content. | Skip to navigation

Personal tools

Navigation

You are here: Home / weblog

Dominic Cronin's weblog

Process Monitor - say goodbye to FileMon and RegMon

Posted by Dominic Cronin at Nov 09, 2006 07:05 PM |

If I were to tell you that there's a new utility that combines the benefit of both FileMon and RegMon, and aces them both, you'd be right to be skeptical, unless of course the new tool came from the same stable. Well there you have it, Sysinternals, newly under the Microsoft umbrella, have re-written these tools, and simultaneously combined and enhanced them.

It's worth the upgrade just to get file and registry activity interleaved in the same view.

You are hereby ordered to immediately download Process Monitor and put it on your USB stick.

Batch-fu

Posted by Dominic Cronin at Nov 08, 2006 11:00 PM |

Batch-fu

Today I had a problem with Tridion Content Porter. This is an application that can be used to move data in and out of the Tridion web content management system. It has an "unattended" mode of operation which allows you to run it from the command line, passing a reference to a configuration file as a parameter. I discovered that sometimes (and if anyone can tell me exactly when that is, I'd be grateful),  if you try to run it this way, instead of "blocking" it returns asynchronously and continues to run in the background, writing data to disk that you'd really rather wait for before you embark on further processing.

I called this in to customer support, but I can't wait for them to fix it, so in the meantime, I cracked my knuckles and settled down to figuring out a workaround for my batch script. This post isn't about Tridion Content Porter; this is a generic technique that you can use in batch scripts for any process that you'd like to give a chance to finish.

This (with most of the irrelevant stuff elided) is what I came up with:

REM Dump out the data using Content Porter
.... ContentPorter.exe .... config.xml .... /unattended

:TEST_FOR_CONTENT_PORTER
for /f "usebackq" %%i in (`tasklist ^| find /C "ContentPorter.exe"`) DO if /I %%i GTR 0 GOTO TEST_FOR_CONTENT_PORTER

REM do something with the exported data
So what's going on here?

Back on the air

Posted by Dominic Cronin at Oct 28, 2006 10:00 PM |

Back on the air

At long last this blog is back on the air. A few weeks ago, I started hearing a deathwatch-beetle-like ticking noise coming from under the television. It turned out to be coming from the hard drive of the server which used to support this web site. To my shame, I didn't have any proper backups. In any case, there's only one right thing to do with a ticking hard drive; it had to go.

In the intervening period, my free time has been taken up with the following tasks, among others:

  • Go out and buy a second hand computer to become my new server
  • Install Gentoo Linux on it.
  • Install and configure Apache, Zope, Plone and EasyBlog

 

Needless to say, it wasn't quite as simple as that, and I've had various technical challenges to overcome along the way. Still, with this web site, or rather cluster of web sites (the same server hosts web sites for the whole family) that's what it says on the tin. One of the primary goals of this activity has always been to erm.. "boldly go".

 

As has been said before, I choose to use technologies that I wouldn't usually encounter in my working life, even though I'm a computer programmer who works mainly with web sites and the software used to manage them. This sometimes means that the home projects are a little amateur, but hopefully not amateurish.

 

Now all I have to do is put some new content on the web sites, and pretty them up. For the content, I'll be trying to recover some of the old data, but don't hold your breath. For the look and feel, well there again, I'll be trying to do things a different way to try and learn something along the way, so I hope it doesn't take too long. In the meantime things are going to look distincly plone-ish around here.

How to set up the location of your .NET .config file when you're doing COM+ interop

Posted by Dominic Cronin at Jul 31, 2006 10:00 PM |
Filed under:

How to set up the location of your .NET .config file when you're doing COM+ interop

Today I was struggling with trying to get my .NET application to pick up it's config file. I'd tried creating a .config in the same directory as the application dll, but it didn't work. This was because the application in question is activated via COM+ interop using the /codebase setting. (In other words, the COM+ settings in the registry tell the COM+ loader to use the CLR, and additionally specify the location of the assembly DLL for the benefit of the .NET loader.) This means that as far as .NET is concerned, the directory isn't the "base" of the application.

 

This was a tough problem, and I might have ended up doing one of two ugly things to solve it:

  • Creating a %windir%/system32/dllhost.exe.config file
  • Adding my configuration settings to machine.config

Either of these would have polluted a much wider area than I'd have liked.

Then I came across a blog entry by Rinat Shagisultanov which gave me sufficient of a clue to find a much better solution. The basic idea is this:

  • Configure the application in COM+ (if necessary adding sufficient System.EnterpriseServices goo to make this work)
  • Create a directory and point to it from the ApplicationRootDirectory setting of the COM+ application
  • Create a .manifest file

Now the CLR will regard that directory as the base of your application, and look there for the config file.

 

Thanks Rinat.

XPath and the dreaded distinction between default namespace and no namespace.

Posted by Dominic Cronin at Jun 12, 2006 10:00 PM |
Filed under:

XPath and the dreaded distinction between default namespace and no namespace.

I thought I was pretty much an old hand at XML by now, and that the standard gotchas wouldn't catch me any more. Not so!  The standardest gotcha of 'em all jumped up out of the slime today like something undead and there I was, gotcha'd again.

 

I suppose I was led astray by putting too much trust in the notion that the methods surfaced in an API would always be relevant. Stupid really, but perhaps if you follow along with the story you'll forgive me.  The API in question was that of the .NET framework; specifically the XmlNamespaceManager class.

Let's say you have some XML like this:

 

<?xml version='1.0'?>
<a:one xmlns:a='aaa'>
	<two xmlns='bbb'/>
</a:one>

 

If you have this in an XmlDocument and you want to XPath to the < two/> element, the first thing you'd usually do is create an XmlNamespaceManager and add the namespaces that you want to use in your XPath expression. This allows you to create a mapping between the namepace prefixes in your expression and the namespaces they represent. In the document itself, the same thing is achieved by the namespace declarations you can see in the sample above, but these don't exist in the XPath expression; it needs its own namespace context, or it won't be able to address anything that's in a namespace. But more of this just now...

 

So there I was today trying to demonstrate some techniques to a colleague, and I wrote some code something like this:

            NameTable nt = new NameTable();
            XmlNamespaceManager nm = new XmlNamespaceManager(nt);
            nm.AddNamespace("a", "aaa");
            nm.AddNamespace(String.Empty, "bbb");

            if (null == doc.SelectSingleNode("a:one/two", nm))
                Console.WriteLine ("Couldn't match default namespace");
            else
                Console.WriteLine ("Matched default namespace");

... and to my horror the match failed. After a few quick changes I had something like this:

            nm.AddNamespace("b", "bbb");
            if (null == doc.SelectSingleNode("a:one/b:two", nm))
                Console.WriteLine("Couldn't match b: namespace");
            else
                Console.WriteLine("Matched b: namespace");

... and on this occasion the match succeeded.

 

What was going on?  Could I possiibly be the first human to set foot on a previously undiscovered bug in the framework? Suffice it to say that my moment of glory will have to wait. A quick hunt around on Microsoft's web site showed that half a dozen other people had reported this as a bug, and that Microsoft's response was "Won't fix."

 

What was going on?

Five or so years ago Martin Gudgin and the other luminaries teaching Developmentor's "Guerilla XML" course, had gone to extraordinary lengths to teach me and my fellow victims the difference between a node that is in a namespace, and one that isn't. Sorry Martin, I failed you.

It turns out that in the XPath standard it says the following

A QName in the node test is expanded into an expanded-name using the namespace
declarations from the expression context.  This is the same way
expansion is done for element type names in start and end-tags except
that the default namespace declared with xmlns is not used: if the QName does not have
a prefix, then the namespace URI is null (this is the same way attribute names are 
expanded).  It is an error if the QName has a prefix for which there is
no namespace declaration in the expression context.

So - in XPath, no prefix means not in any namespace at all, just like for attributes. Microsoft's implementation is correct. Otherwise, if you had XML like this:

<?xml version='1.0'?>
<one>
	<two xmlns='bbb'>
		<c:three xmlns:c="po"/>
	</two>
<one>

... you'd be unable to write an XPath from the root element down to <c:three/>.

 

Now for the part where you forgive me for my stupidity:

If you look at the documentation for XmlNamespaceManager, it states very clearly that you can use the empty string to set the Default namespace. (To be fair, the documentation for selectSingleNode has a note which attempts to clarify matters.)

 

If you look at the rest of the API of XmlNamespaceManager, the reason for the confusion becomes clear. XmlNamespaceManager also supports methods like PushScope, GetNamespacesInScope, etc. which plainly aren't intended for use with XPath at all. It looks rather as though you could use an XmlNamespaceManager for managing your namespaces as you navigate through an XmlDocument, perhaps with a streaming library. In that context, setting the default namespace makes perfect sense. If you're using it with XPath though, it's completely irrelevant.

 

So repeat after me: A default namespace isn't the same thing as the empty namespace (aka null namespace, no namespace, not in a namespace, etc.)

Pulling website information out of the IIS metabase

Posted by Dominic Cronin at May 24, 2006 10:00 PM |
Filed under: , , ,

Pulling website information out of the IIS metabase

Someone recently asked me how to find the URL where the Tridion user interface is running. The idea was to automate the set-up for Tridion Site-Edit. The following snippet of code doesn't solve their problem, but for me it was a bit of fun exploring how to pull up this data out of the IIS metabase using C#. Although this blog entry is categorised as "Tridion", this code isn't particularly Tridion-specific. It's sufficient to show that it's not particularly painful to work with IIS programatically. You can also write to the metabase using similar techniques.

 

using System;
using System.Collections.Generic;
using System.Text;
using System.DirectoryServices;

namespace Hinttech.Dotnet.Samples.WebSiteDumper
{
    class Program
    {
        static void Main( string[] args )
        {
            using (DirectoryEntry webServers = new DirectoryEntry("IIS://localhost/W3SVC"))
                {
                foreach( DirectoryEntry server in webServers.Children)
                {
                    PropertyValueCollection serverComment = server.Properties["ServerComment"];
                    if ( serverComment.Value != null && serverComment[0].ToString() == "Tridion Content Manager")
                    {
                        Console.WriteLine("The Tridion web site is running on: ");
                        Console.WriteLine("===================================");
                        // If you want the https sites too, you need to do the same thing for "SecureBindings"
                        foreach ( string serverBinding in server.Properties["ServerBindings"] )
                        {
                            string[] serverBindingParts = serverBinding.Split(':');
                            string ipAddress = serverBindingParts[0];
                            string port = serverBindingParts[1];
                            string hostHeader = serverBindingParts[2];
                            if (string.IsNullOrEmpty(ipAddress))
                            {
                                ipAddress="Default";
                            }
                            Console.WriteLine(
                                "\tIP Address = {0}\n\tPort= {1}\n\tHostHeader= {2}",
                                ipAddress, port, hostHeader );
                            Console.WriteLine("===================================");
                        }                                            
                        server.Dispose();
                        break;                        
                    }
                server.Dispose();
                }
	    }

#if DEBUG
            Console.ReadKey();
#endif
        }
    }
}

Xml namespace weirdness in MSXML4

Posted by Dominic Cronin at Apr 28, 2006 10:00 PM |
Filed under:

Xml namespace weirdness in MSXML4

This post has been a while brewing. It began a few months ago when I was working on a project with my colleague Rob Wittenbols. He was building an XML document using the MSXML4 DOM API, and he wanted to have the same degree of control over where namespace prefixes would be declared as if he was deserializing the document from a text file. We discussed the subject briefly and then went off to do other things. Later in the day, we'd obviously both been pondering the issue, and had come up with different answers.

I had looked at the API and discovered that it was impossible to do what he wanted. The API didn't support it. You could create a node, and put it in a namespace, and even give that node a prefix, but you couldn't declare another namespace prefix at the same time. That made perfect sense, I said, because namespace prefixes were purely to do with the serialized view of the document, and where they were declared was generally irrelevant when working in the DOM. As long as you could get each element in to the correct namespace, you'd be fine.

Rob had taken an almost opposite view, and come up with a bit of practical hackery that blew my theoretical argument out of the water. He'd just escaped the final quote of his namespace value and carried on to add another one. Something like this:

dom.createNode(1, "xxx:child", "xxx"" xmlns:y=""yyy")

(Surprisingly to me) this worked, and allowed him to achieve what he wanted, and I couldn't argue with him because his program was intended to output serialized XML and he wanted it in a particular way. To be fair, a good DOM implementation would provide a clean way to do this. (OK - this is an edge case, and in many other respects MSXML4 is an excellent implementation.)

Getting back to theoretical niceties, I went up and looked up the recommendations for XML namespaces. A namespace name must be a URI as defined in RFC2396, and there the use of double quotes is excluded from use in a URI:

  The angle-bracket "<" and ">" and double-quote (") characters are excluded because they are often used as the delimiters around URI in text documents and protocol fields.

 

So strictly, Rob's hack is cheating :-) , but it got the job done for him. (Note that in this context we don't have to worry about the single-quote character (') because when MSXML4 serializes the Dom, it uses double-quotes to delimit the namespace name.)

The current recommendation, XML Namespaces 1.1, specifies that a namespace name should be an Internationalized Resource Identifier, and the standard for those (currently a draft) doesn't mention double-quotes at all.

 

Not long after this discussion, I almost got as far as writing about it when Don Box made a posting on a related topic, asking how namespaces ought to be compared for equivalence, as the Microsoft implementations do not perform encoding or unencoding when comparing. The responses were fairly clear. The Microsoft implementation is correct in this respect: Namespaces are compared as strings.

To quote from XML Namespaces 1.1:

IRI references identifying namespaces are compared when determining whether a name belongs to a given namespace, 
and whether two names belong to the same namespace. [Definition: The two IRIs are treated as strings, and they are
identical if and only if the strings are identical, that is, if they are the same sequence of characters.] 
The comparison is case-sensitive, and no %-escaping is done or undone.

So that's pretty straightforward. When comparing namespaces for equivalence, you don't do anything with the string. Having said that, I think the implementation of MSXML4 is broken. It should check for the double-quote character. Here's a snippet of vbscript that shows why:

Set dom = CreateObject("Msxml2.DOMDocument.4.0")
dom.async = false
dom.loadXML "<?xml version='1.0'?><root/>"
Dim child
' VBScript escapes double-quote as double double-quote
Set child = dom.createNode(1, "xxx:child", "xxx"" xmlns:y=""yyy")
dom.documentElement.appendChild child
dom.setProperty "SelectionNamespaces", "xmlns:a='xxx' xmlns:b='yyy'"

' This XPath will fail, as 'xxx' is not the same as 'xxx"" xmlns:y=""yyy"'
If dom.selectSingleNode("//a:child") is nothing then
    WScript.Echo "Can't xpath to xxx:child"
Else
    WScript.Echo "Can xpath to xxx:child"
End if 

dom.save "c:\temp\tempdom.xml"
dom.load "c:\temp\tempdom.xml"

' The rather bizarre namespace name doesn't survive the round-trip to disk, and this XPath succeeds
If dom.selectSingleNode("//a:child") is nothing then
    WScript.Echo "Can't xpath to xxx:child"
Else
    WScript.Echo "Can xpath to xxx:child"
End if 

Its this inconsistency that makes me say it's broken. The document represented by your DOM should always survive a round-trip via the serialization mechanism. Either the serialization mechanism has to find some way to represent the namespace name with the double-quote in it, (Is there any reason why you couldn't say <xxx:child xmlns:xxx="xxx&quot; xmlns:y=&quot;yyy"/>) or you have to regard the double-quote as illegal in a namespace name.

 

That's just the purist in me speaking. On the other hand, I can't think of a good use case where a mended implementation would be better than the currently broken one. At least the broken version lets Rob serialize how he wants.

Benefits of continuous integration

Posted by Dominic Cronin at Apr 05, 2006 10:00 PM |

Joanna Rothman notes the following benefits of continuous integration:

 

  • Continuous integration provides early feedback to developers.
  • The PM can see every day if the build is broken. (I use this as a predictive metric.)
  • There's less to check in every day, so it's easier to see where the problems that broke the build occurred.
  • It's much more obvious earlier whether we have enough tests to know if the build is any good.

 

 

and asks us if we have more to add.

 

For myself I'd note the following:

 

  • Developer morale benefits from knowing that there isn't an invisible mountain looming up in front of you
  • Those who mess things up are forced immediately to switch their efforts to undoing their evil, which (hopefully) means they can't be busy digging a deeper hole
  • Developer morale benefits from knowing that if you are the one to screw up, the scope of your crime will be small enough that no-one will actually hate you for it (unless you screw up a lot)
  • If you screw up a lot - there's no-where to hide. Developer morale benefits again.

Total quality

Posted by Dominic Cronin at Mar 25, 2006 11:00 AM |
Filed under:

Total quality

I used to work in manufacturing industry. I made cookers and fridges, and mechanical excavators, and bits of trains. I was a manufacturing engineer, and I spent my time trying to make it better. Much like now, when I'm a computer programmer (hey, that shit was 15 years ago or something), and every day I'm trying to make it better.

Back then, it was a given that it was impossible to ship a 100% defect-free car (or substitute for car any manufactured item of equivalent complexity). Nowadays, it's a given that you can't ship defect-free software (or at least that it would be prohibitively expensive to do so).

So when you buy a car nowadays, how likely do you think it is that you'll be able to drive it for at least six months without taking it to the garage? Pretty likely eh?

And now to the crux of it - we've come to accept that it's impossible (or commercially infeasible) to produce defect-free software. Fifteen or so years ago, the Japanese motor companies started shipping defect-free cars as a matter of routine. The rest of the world's car manufacturers couldn't hide any more. They had to start doing the same thing.

Software development techniques are at a similar crossroads right now, with test driven development etc. Who will be the first to start routinely delivering 100% defect-free software products?

Who said it couldn't be done?

Component linking and magical parameters in Tridion's XSLT component templates

Posted by Dominic Cronin at Jan 28, 2006 11:00 PM |
Filed under: ,

I was recently asked a question about XSLT templating in Tridion. The question was about how you create component linking code from within your XSLT component template. The tricky part is that you need a publication ID and a component template ID. My solution involved getting these in the page template and passing them in to the XSLT as parameters. OK - job done - it's just coding from there eh? Well yes - but it didn't stop being interesting at that point, because my questioner in the meantime had come up with his own solution based on some sample code that he'd found on the Tridion forum. He hadn't needed to add the parameters himself, because Tridion adds some parameters for you as if by magic.

 

It turns out that if you include any of the following three global parameters at the top of your XSLT, Tridion will add the corresponding DOMs as parameters as if by magic.

<xsl:param name="tcm:Page"/>
<xsl:param name="tcm:Publication"/>
<xsl:param name="tcm:ComponentTemplate"/>

This is very cool, and saves you the effort of coding it, but I don't know whether it's a supported feature. I suppose it should be, because it's really just the standard behaviour for a component template translated to XSLT. I just can't find it anywhere in the documentation.

 

There is a gotcha, mind you! Although the parameters are declared in the "tcm:" namespace, which resolves to "http://www.tridion.com/ContentManager/5.0", don't be tempted to use a prefix other than "tcm:" for this namespace. If you do, you'll find that there's something broken; the parameters don't seem to be added automatically. (Tested on R51SP4) Still - as it's an undocumented, and perhaps unsupported feature, we can't really complain.

 

It would make a good enhancement request though. Perhaps Tridion can be persuaded to document this and support it. In the meantime, perhaps it's better to be on the safe side and explicitly add the parameters you need to the Component Presentation from the Page Template.