Thursday, September 30, 2010

Rethrowing Exceptions Without Losing Original Stack Trace

Everyone knows you should never ‘throw err’:

    try

    {

        // Do something bad

    }

    catch(Exception err)

    {

        // Some error handling, then…

        throw err;

    }

 

…because you overwrite the original stack trace, and end up with no idea what happened where. If you want to re-throw, you just ‘throw’ within the catch block, and the original exception is re-throw unmodified (or wrap-and-throw).

But that’s within the catch block. What do you do if you need to re-throw an exception outside the catch, one you stored earlier? This is exactly what you have to do if you’re implementing an asynchronous (APM / IAsyncResult) call, or marshalling exceptions across app domain / remoting boundaries.

The runtime manages this just fine by ‘freezing’ the exception stack trace. When rethrow, the new stack trace is just appended to the old one – that’s what all those ‘Exception rethrow at [0]’ stuff is in the stack trace. But the method it uses to do this (Exception.PrepForRemoting) is internal. So unfortunately in order to use it, you have to call it by reflection:

    public static void PrepForRemoting(this Exception err)

    {

        typeof(Exception).InvokeMember(

            "PrepForRemoting",

            BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod,

            (Binder)null, err, new object[0]);

    }

 

    /// <summary>

    /// Rethrow an exception without losing the original stack trace

    /// </summary>

    [DebuggerStepThrough]

    public static void Rethrow(this Exception err)

    {

        err.PrepForRemoting();

        throw err;

    }

Evil I here you cry? Well suck it up, because that’s exactly what Rx does in System.CoreEx:

image

(Tasks in .Net 4 side-step this problem by always wrapping exceptions in a new AggregateException prior to throwing – this also allows a Task to accumulate multiple exceptions throughout its lifecycle, depending on the continuations applied)

Sunday, September 19, 2010

Reacting to Rx

I’ve finally got round to spending a bit of time looking at Rx over the weekend, and my head is still spinning as to just how fantastically relevant this is to some of the stuff I’m working on right now. If have no idea what Rx is, check out these brief Channel 9 videos:

The first will get you interested, the second will make the penny drop[1].

So anyway, I have a class called a MessagePump<T>. Its job is to abstract away a lot of low-level socket guff (fragmentation, parsing etc…) and just deliver messages as they are read off a socket. It basically just sits in a big async loop of BeginRead / EndRead operations, constantly passing itself as the callback (ie never ‘owning’ a thread).

That’s all it does, so to deliver messages into the rest of the system it exposes a MessageReceived event. And sometimes a message might not parse properly, probably someone got out of sync whatever, so there’s a ExceptionReceived event. Oh, and if you get a zero-byte read from BeginRead that means the socket the other end closed, so there’s a Disconnected event

  • MessageReceived(object, EventArgs<T>)
  • ExceptionReceived(object, EventArgs<Exception>)
  • Disconnected(object, EventArgs)

Now compare this to Rx’s IObserver<T> interface:

  • OnNext(T)
  • OnError(Exception)
  • OnCompleted()

It’s like completely the same. I guess there are only so many ways to skin a cat, but I wasn’t expecting it to be quite so aligned. Hopefully I can read this as saying my design is basically sound.

But whatever, what it really means is that dropping in Rx is going to be a bit of a doddle. In fact because the IObserver<T> and IObservable<T> interfaces (alone) are part of the .net 4 framework, even without Rx I can implement the pattern (just without the Rx fruit),which makes leveraging Rx later on (e.g. to filter with Linq) an option for the consumer.

And because the IObserver<T> / IObservable<T> pattern is much more amenable to composition than a raw .net event (which is really, the whole point of Rx), we can use containers like MEF to attach the subscribers at runtime, with (what seems to be) relative ease.

Both temporal and binary decoupling. Cool.

 

[1] For example: did you ever write something like an auto-complete popup? You want to wait a while after each keystroke in case the user didn’t finish typing yet (about 500ms I think). I ended up writing a general-purpose event-buffer class, that only propagated the event after a specified inactivity period (this also worked great for file change notifications). In Rx this is trivial: just use the ‘Throttle’ linq operator over the event sequence. See the hands-on-lab

Saturday, September 18, 2010

Problems With Stuff

image

Being charitable you might point out that as a technology becomes increasingly pervasive it inevitably ends up in the hands of less technically savvy users, but I like to think of it as ‘all our stuff is still a bit crap’.

Wednesday, September 08, 2010

.Net 4 not supported on Windows 2008 Server Core

There is an explanation from the .net SKU owner as to why (which I don’t entirely follow), but the bottom line is that what the download page says is right – it’s just not available. So no Distributed Cache either.

Poo.

(It does support a subset of the net 3.5 functionality, largely orientated towards ASP.Net support – there’s a basic explanation of which bits here)

Visual Studio 2010 build spew in DebugView

If you’re a fan of DebugView (like me) you’d have been driven spare by the reams of spurious debug output that VS 2010 generates when doing a build: some 15,000 lines (in my case) of repeated cruft that drowns your output:

*** HR originated: -2147024774
*** Source File: d:\iso_whid\x86fre\base\isolation\com\copyout.cpp, line 1302


*** HR propagated: -2147024774
*** Source File: d:\iso_whid\x86fre\base\isolation\com\enumidentityattribute.cpp, line 144



This is a known issue on the forums, and there is a Connect Issue associated with it, so please vote for it. Hopefully it’s not too late to get this fixed in SP1.



(I’m optimistic– the bug was raised by Rusty Miller, an (erstwhile?) tester on the VS team)

Tuesday, September 07, 2010

TechEdAu 2010

It was only the week before last, but already I feel the clarity slipping away like a dream in the morning. Ahem. It was quite an interesting year, because apart from Windows Mobile 7, most of the stuff that was being talked about actually exists at RTM today, which was a nice change from learning about stuff you might get to use in 6 month’s time.

Memes this year:

  • Devices are ‘windows’ to the cloud [1]
  • Virtualisation, virtualization, virtualization
  • All I want for Christmas is Windows Mobile 7

Anyway, here’s what I went to

Day 1:

Day 2:

Day 3:

And here’s all the sessions I will be catching up on Online (as and when the videos come up):

…and a couple from TechEd North America that looked fairly promising:

Phew.

 

[1] If you think this cloud stuff is finally becoming the William Gibson / Ian M Banks model of pervasive cyberspace, you’d be right.

Saturday, September 04, 2010

Which WPF Framework?

So it’s way past time that I actually started getting used to a WPF framework, rather than keep re-inventing the wheel. But where to start? I thought it was just between Prism and Caliburn, but then I found WAF, and then researching that I found a whole bunch of others.

I suspect I’ll start with WAF because it describes itself as lightweight. Prism comes from the P&P team, who are normally anything but, and Caliburn supports paradigms other than MVVM, which just seems a bit pointless.

Tuesday, August 10, 2010

PowerDbg is search result #7 for ‘WinDbg’

Ok, this is only on MSDN search, but still that seems pretty damn high:

image

Mind you, we’re #38 on Bing, and #14 on Google so we’re not completely inconspicuous.

Time to pull our fingers out and finish off v6 I think.

Thread Safety in MSDN

Just what exactly is the point of even having a ‘thread safety’ comment in the MSDN doco, if it’s just blatant boiler-plate drivel.

Take, for example, System.Text.ASCIIEncoding. Generally speaking there’s only one of these in play at any one time, because the Encoding.ASCII static property is a singleton (as they all are):



public static Encoding ASCII
{
[TargetedPatchingOptOut(...)]
get
{
if (asciiEncoding == null)
{
asciiEncoding = new ASCIIEncoding();
}
return asciiEncoding;
}
}



So you’d better damn well hope it’s thread safe, otherwise all those concurrent write operations you’re doing, they’re screwed, right? But what does MSDN have to say on the subject:




“Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.”




Oh. Really helpful. Thanks a bunch.



Looking at the usage patterns through the Framework Class Libraries, it’s pretty clear they are thread-safe. Encoding.GetEncoding(int) hands out references to the singletons, which are similarly used with gay abandon in System.IO.Ports.SerialPort, System.IO.File.ReadAllLines, various StreamReader overloads etc… (though BinaryReader chooses to new up its UTF8Encoding, heaven knows why). And the sky would have fallen by now if these usages weren’t at least largely correct.



But poking about in Reflector is clearly not a substitute for accurate documentation, and the ‘parallel processing revolution’ everyone keeps going on about is clearly not going to work if we just keep trotting out the ‘instances members are not guaranteed to be thread safe’ line.



System.Text.Encodings: believed to be thread-safe.

Tuesday, July 27, 2010

Log4Net Active Property Values via Lamdas

Some years ago I wrote a couple of posts on some nasty problems that you could encounter if using log4net contexts in an environment where you didn’t control the thread lifecycle, say ASP.Net. Judging by the amount of coverage it got at the time (and still) I wasn’t the only person caught out by this.

Anyway I was doing something similar recently, not in ASP.Net, but in a Windows Service application with lots of threads. It’s the same kind of problem: there’s some thread-specific context that always exists, which we want to make available to log4net, but putting it in ThreadLocalContext doesn’t really work very well because we’d have to set them up in all our thread-entry methods, which would be everywhere where a callback gets entered – very messy in our (highly asynchronous) application.

Instead I wanted to put something in log4net’s GlobalContext that resolved to the thread’s context value. And actually now we’ve got lamdas and all that nice stuff, I was able to come up with a significantly neater implementation for a general-purpose contextual logging property, which basically answers the original ASP.Net problem too:

 

    /// <summary>

    /// Implements a class that can be used as a global log4net property

    /// to resolve an action to a string at event-fixing-time

    /// </summary>

    /// <remarks>With a suitable lamda expression, you can put this

    /// into your log4net.GlobalContext to resolve at logging time to a variety

    /// of stuff you might want to use in your logging statements.

    /// <example>Using threadId (not thread Name) as a property:<code>

    /// log4net.GlobalContext.Properties["threadId"] =

    /// new Log4NetContextProperty(() => Thread.CurrentThread.ManagedThreadId.ToString());

    /// </code></example>

    /// </remarks>

    public class Log4NetContextProperty : IFixingRequired

    {

        private readonly Func<string> _getValue;

 

        public Log4NetContextProperty(Func<string> getValue)

        {

            _getValue = getValue;

        }

 

        public override string ToString()

        {

            return _getValue();

        }

 

        public object GetFixedObject()

        {

            return ToString();

        }

    }

In this case I wanted ‘threadId’ as a logging property (log4net exposes thread name, which is normally fine, but the R# test runner creates woppingly long thread names that basically hide the actual logging message, and I really just wanted the IDs (hence the example above). But you can see how you can basically use this to expose any context data to log4net if you wanted to.

Wednesday, July 21, 2010

64 Bit Explained

Look, it’s really not that hard.

Programs are still in the same place, in %ProgramFiles%, unless you need the 32 bit version, which is in %ProgramFiles(x86)%, except on a 32 bit machine, where it’s still %ProgramFiles%.

All those dll’s are still in %SystemRoot%\System32, just now they’re 64 bit. The 32 bit ones, they’re in %SystemRoot%\SysWOW64. You’re with me so far, right? Oh, and the 16 bit ones are still in %SystemRoot%\System – moving them would just be weird.

Registry settings are in HKLM\Software, unless you mean the settings for the 32 bit programs, in which case they’re in HKLM\Software\Wow6432Node.

So the rule is easy: stick to the 64 bit versions of apps, and you’ll be fine. Apps without a 64 bit version are pretty obscure anyway, Office and Visual Studio for example[1]. Oh, and stick to the 32 bit version of Internet Explorer (which is the default) if you want any of your add-ins to work. The ‘default’ shortcut for everything else is the 64 bit version. Having two shortcuts to everything can be a bit confusing, so sometimes (cmd.exe) there’s only the one (64 bit) and you’ll have to find the other yourself (back in SysWOW64, of course). And don’t forget to ‘Set-ExecutionPolicy RemoteSigned’ in both your 64 bit and 32 bit PowerShell environments.

Always install 64 bit versions of drivers and stuff, unless there isn’t one (MSDORA, JET), or you need both the 32 bit and 64 bit versions (eg to use SMO / SqlCmd from a 32 bit process like MSBuild). Just don’t do this if the 64 bit installer already installs the 32 bit version for you (like Sql Native Client).

Anything with a ‘32’ is for 64 bit. Anything with a ‘64’ is for 32 bit. Except %ProgramW6432% which is the 64 bit ProgramFiles folder in all cases (well, except on a 32 bit machine). Oh and the .net framework didn’t actually move either, but now it has a Framework64 sibling.

I really don’t understand how people get so worked up over it all.

 

[1] Ok, so there is a 64 bit version of Office 2010, but given the installer pretty much tells you not to install it, it doesn’t count.

Monday, July 19, 2010

P/Invoke Interop Assistant

P/Invoke is like a poke in the eye. Sure the P/Invoke wiki made life a lot more palatable, but it’s at best incomplete, at worst inaccurate, and invariably you’ll find yourself hand-crafting signatures based on Win32 API doco and bringing a production server to its knees because of a stack imbalance.

In my idler moments I’ve often thought that surely parsing the source-of-truth Win32 header files and spitting out P/Invoke signatures couldn’t be that hard. Fortunately for everyone, the Microsoft Interop Team thought so too[1], and released the P/Invoke Interop Assistant to Codeplex. Actually that was about 2 years ago, but I only just noticed, so it’s still exciting for me.

As I understand it this has been made easier because Microsoft have been standardizing their header files and adding some additional metadata [2], which makes it possible to generate accurate signatures (and, presumably, to generate MSDN doco).

Sadly of course, none of this does anything to make any of the underlying API’s any easier to use…

 

[1] Actually if you look on Wikipedia, turn’s out there’s a fair few around.
[2] In retrospect you wonder why managed code took so long to take off as a concept, given how enormously fragile the previous paradigm actually was. SAL’s a great idea, but only highlights how fundamental the problem is.

Friday, June 11, 2010

Converting to Int

You wouldn’t have thought that such as basic operation as turning a double into an integer would be so poorly understood, but it is. There are three basic approaches in .Net:

  • Explicit casting, i.e. (int)x
  • Format, using String.Format, or x.ToString(formatString)
  • Convert.ToInt32

What’s critical to realise is that all of these do different things:

    var testCases = new[] {0.4, 0.5, 0.51, 1.4, 1.5, 1.51};

    Console.WriteLine("Input  Cast   {0:0}  Convert.ToInt32");

    foreach (var testCase in testCases)

    {

        Console.WriteLine("{0,5} {1,5} {2,5:0} {3,5}", testCase, (int)testCase, testCase, Convert.ToInt32(testCase));

    }

Input  Cast   {0:0} Convert.ToInt32
0.4 0 0 0
0.5 0 1 0
0.51 0 1 1
1.4 1 1 1
1.5 1 2 2
1.51 1 2 2


As my basic test above shows, just casting is the equivalent of Math.Floor – it looses the fraction. This surprises some people.



But look again at the results for 0.5 and 1.5. Using a format string rounds up[1], to 1 and 2, whereas using Convert.ToInt32 performs bankers rounding[2] (rounds to even) to 0 and 2. This surprises a lot of people, and you’d be forgiven for missing it in the doco (here vs. here):



Even more interesting is that PowerShell is different, in that the [int] cast in PowerShell is the same as a Convert.Int32, not a Math.Floor():



> $testCases = 0.4,0.5,0.51,1.4,1.5,1.51
> $testCases | % { "{0,5} {1,5} {2,5:0} {3,5}" -f $_,[int]$_,$_,[Convert]::ToInt32($_) }

Input Cast {0:0} Convert.ToInt32
0.4 0 0 0
0.5 0 1 0
0.51 1 1 1
1.4 1 1 1
1.5 2 2 2
1.51 2 2 2


This is a great gotcha, since normally I’d use PowerShell to test this kind of behaviour, and I’d have seen the wrong thing (note to self: use LinqPad more)



 



[1] More precisely it rounds away from zero, since negative numbers round to the larger negative number.



[2] According to Wikipedia bankers rounding is a bit of a misnomer for ‘round to even’, and even the MSDN doco on Math.Round seems to have stopped using the term.

Thursday, June 03, 2010

Splatting Hell

Recently both at work and at home I was faced with the same problem: a PowerShell ‘control’ script that needed to pass parameters down to an arbitrary series of child scripts (i.e. enumerating over scripts in a directory, and executing them in turn).

I needed a way of binding the parameters passed to the child scripts to what was passed to the parent script, and I thought that splatting would be a great fit here. Splatting, if you aren’t aware of it, is a way of binding a hashtable or array to a command’s parameters:

# ie replace this:
dir -Path:C:\temp -Filter:*

# with this:
$dirArgs = @{Filter="*"; Path="C:\temp"}
dir @dirArgs

Note the @ sign on the last line. That’s the splatting operator (yes, its also the hashtable operator as @{}, and the array operator as @(). It’s a busy symbol). It binds $dirArgs to the parameters, rather than attempting to pass $dirArgs as the first positional argument.

So I thought I could just use this to pass any-and-all arguments passed to my ‘master’ script, and get them bound to the child scripts. By name, mind, not by position. That would be bad, because each of the child scripts has different parameters. I want PowerShell to do the heavy lifting of binding the appropriate parameters to the child scripts.

Gotcha #1

I first attempted to splat $args, but I’d forgotten that $args is only the ‘left over’ arguments after all the positional arguments had been taken out. These go into $PSBoundParameters

Gotcha #2

…but only the ones that actually match parameters in the current script/function. Even if you pass an argument to a script in ‘named parameter’ style, like this:

SomeScript.ps1 –someName:someValue

…if there’s no parameter ‘someName’ on that script, this goes into $args as two different items, one being ‘-someName:’ and the next being ‘someValue’. This was surprising. Worse, once the arguments are split up in $args they get splatted positionally, even if they would otherwise match parameters on what’s being called. This seems like a design mistake to me (update: there is a Connect issue for this).

Basically what this meant was that, unless I started parsing $args myself, all the parameters on all the child scripts had to be declared on the parent (or at least all the ones I wanted to splat).

Gotcha #3

Oh, and $PSBoundParameters only contains the named parameters assigned by the caller. Those left unset, i.e. using default values, aren’t in there. So if you want those defaults to propagate, you’ll have to add them back in yourself:

function SomeFunction(
    $someValue = 'my default'
){
    $PSBoundParameters['someValue'] = $someValue

Very tiresome.

Gotcha #4

$PSBoundParameters gets reset after you dotsource another script, so you need to capture a reference to it before that :-(

Gotcha #5

Just when you thought you were finished, if you’re using [CmdLetBinding] then you’ll probably get an error when splatting, because you’re trying to splat more arguments than the script you’re calling actually has parameters.

To avoid the error you’ll have to revert to a ‘vanilla’ from an ‘advanced’ function, but since [CmdLetBinding] is implied by any of the [Parameter] attributes, you’ll have to remove those too :-( So back to $myParam = $(throw ‘MyParam is required’) style validation, unfortunately.

(Also, if you are using CmdLetBinding, remember to remove any [switch]$verbose parameters (or any others that match the ‘common’ cmdlet parameters), or you’ll get another error about duplicate properties when splatting, since your script now has a –Verbose switch automatically. The duplication only becomes an issue when you splat)

What Did We Learn?

Either: Don’t try this at home.

Or: Capture PSBoundParameters, put the defaults back in, splat it to child scripts not using CmdLetBinding or being ‘advanced functions’

Type your parameters, and put your guard throws back, just in case you end up splatting positionally

Have a lie down

Viewing MDX Data with WPF (redux)

Spend most of the day today grappling with binding a WPF datagrid to a DataSet loaded from a parameterized MDX query.

The first gotcha was that SSAS expects its parameterized queries to be passed using the ICommandWithParameters interface, however the OleDb provider for .Net doesn’t support named parameters (except for sprocs). This is a ‘fixed’ Connect issue – fixed as in ‘still broken in .Net 4 but marked as fixed because we can’t be bothered’.

Ahem.

So rather than use ado.net parameters, I’m now using string replacement on my source query text. Just great:

    // So have to do manual parameterization :-(

    query = query

        .Replace("@date", dateKey)

        .Replace("@time", timeKey)

        ;

Then of course the WPF data grid wouldn’t show the data (despite the DataSet visualizer working just fine). It bound and showed columns just fine using AutoGenerateColumns:

    dataGrid1.ItemsSource = dataSet.Tables[0].DefaultView;

 

image

…but all the rows showed blank!

Eventually I noticed a spew of debug output, listing the binding failures:

System.Windows.Data Error: 17 : Cannot get 'Item[]' value (type 'Object') from '' (type 'DataRowView'). BindingExpression:Path=[Blah1].[Blah2].[Blah3].[MEMBER_CAPTION]; DataItem='DataRowView' (HashCode=66744534); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String') TargetInvocationException:'System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentException: Blah1 is neither a DataColumn nor a DataRelation for table TheTableName.

at System.Data.DataRowView.get_Item(String property)

--- End of inner exception stack trace ---

This all seemed awfully familiar, and fortunately I happened across a helpful blog article (which I wrote!) explaining the problem. This time it is AutoGenerateColumns that’s generated the wrong binding path, causing WPF to try and find ‘deep’ members (attempting to walk multiple indexers) rather than just bind to a column with that name.

The fix is something like this:

    // This works

    var table = dataSet.Tables[0];

    dataGrid1.Columns.Clear();

    dataGrid1.AutoGenerateColumns = false;

    foreach (DataColumn dataColumn in dataSet.Tables[0].Columns)

    {

        dataGrid1.Columns.Add(new DataGridTextColumn

        {

              Header = dataColumn.ColumnName,

              Binding = new Binding("[" + dataColumn.ColumnName + "]")

        });

    }

    dataGrid1.ItemsSource = table.DefaultView;

Grr.

Tuesday, June 01, 2010

One-line TODO Extractor in PowerShell

I previously wrote a PowerShell TODO extractor, that blasts through an entire source hierarchy looking for TODOs, and reports them to the console, complete with a few lines of context either side so you can tell what you’re looking at. It was like, 20 lines of code.

Well blow me if v2 just doesn’t do it out of the box:

PS > dir . -filter:*.cs -recurse | select-string "\sTODO\s" -context:4 -CaseSensitive

Monday, May 31, 2010

What’s New In PowerShell 2

At work, where I do most of my PowerShell, we’ve only just shifted off XP, so until recently I’d not really looked much into the differences between PowerShell 1 and 2. The ISE is pretty good (its a debugger!), support for webservices is a few years too late (but very welcome) and I can see Remote PowerShell being pretty useful.

So I’d not really been keeping up. If anything I was deliberately ignoring it, to avoid the temptation to write something that would require upgrading the server. But eventually, I cracked[1].

Oh My God.

Put aside for the moment the absolute avalanche[2] of new cmdlets (write-verbose, out-gridview, select-xml[3], measure-object etc…), and put aside for the moment support for background jobs, the wonderful -split and -join operators, and even put aside how tab-completion now works for .net static methods...

Tab completion now works for script functions and their parameters. You can type in a function on one line, and be happily tab-completing it on the next. You can even add comment-based or XML help, though probably not at the console.

Once again, PowerShell rocks

 

[1] Blame PowerDbg

[2] Some guy[4] is writing a blog series on every new cmdlet!

[3] Select-Xml: Here’s one I used today at work to get all the references from all the C# project files within a folder hierarchy. Sure you could do it all before with XmlDocument, but check this out:

PS > dir . -filter:*.csproj -Recurse | `
Select-Xml -XPath:'//*[local-name() = "Reference"]' | `
Select-Object -ExpandProperty Node

Include
-------
System
System.Core
System.Xml.Linq
System.Data.DataSetExtensions
System.Data
System.Xml

[4] He’s called Jonathan Medd, but the ‘some guy’ thing has a certain ring to it…

[5] Oh, and proper try{}catch{}finally{} error handling. I missed that

Friday, May 28, 2010

Problems Running Tests When Preserving Output Directory Structure with Team Build

Previously I’ve posted about how to override the Team Build default output directory scheme and produce something a bit more sane.

Unfortunately if you do implement this it can break the built-in test run task, and most of the recipes related to it. You’ll get the following error in your build logs:

MSBUILD : warning MSB6003: The specified task executable "MSTest.exe" could not be run. The directory name is invalid

If you run the build with /verbosity:detailed to see the actual args passed to MSTest.exe, and then run MSTest yourself interactively, you’ll see the real underlying error:

Directory "(my build path)\Binaries\Debug" not found.
For switch syntax, type "MSTest /help"

The problem here is that (as detailed on the TestToolsTask doco) the team foundation build targets sets up MSTest.exe with SearchPathRoot="$(OutDir)", ie $(BinariesRoot)\$(Configuration). But if you overrode CustomizableOutDir and never actually copied the binaries out to the output folder that directory will never get created.

Fix 1:

If you’re not really using CustomizableOutDir, remove it. Reverting to the default Team Build directory structure is the simplest way of getting the tests to be located and executed and everything to ‘play nice’.

Fix 2:

Make sure that if your TFBuild.proj says CustomizableOutDir you do actually have the corresponding custom tasks in the individual projects to copy the binaries (see my previous post), otherwise you end up with no output whatsoever, and the test task will fail.

Fix 3:

If you want CustomizableOutDir but want to be robust to the possibility that your project builds may not populate the output directory structures properly, you can hack your build to run the tests out of the source \bin\debug folders.

My first pass was just to add the following to my BeforeTestConfiguration target (that I’d added from the Running Unit Tests without a Test List recipie):

    <!--because this is what the TestTask gets its SearchPath set to, it must exist-->

    <MakeDir Directories="$(OutDir)"/>

But that wasn’t good enough on its own, because now the error was:

CoreTestConfiguration:
File "..\..\(blah)\bin\Debug\Assembly.UnitTests.dll" not found

The relative paths to the test assemblies were correct relative to the $(SolutionDir), but not relative to the $(OutDir). So, for want of a better answer, I just overwrite OutDir for the duration of the test task:

   <!—defined elsewhere-->

   <TestsToRun Include="$(SolutionRoot)\%2a%2a\bin\$(Configuration)\%2a.UnitTests.dll" />

 

  <Target Name="BeforeTestConfiguration">

    <!-- normal bits as per the recipe-->

    <Message Text="Using tests from @(TestsToRun)" Condition=" '$(IsDesktopBuild)'=='true' " />

 

    <CreateItem Include="@(TestsToRun)">

      <Output TaskParameter="Include" ItemName="LocalTestContainer"/>

      <Output TaskParameter="Include" ItemName="TestContainer"/>

    </CreateItem>

 

    <Message Text="LocalTestContainer: @(LocalTestContainer)" Condition=" '$(IsDesktopBuild)'=='true' " />

 

    <!--Fix to allow use of CustomizableOutDir -->

    <MakeDir Directories="$(OutDir)"/>

    <PropertyGroup>

      <OldOutDir>$(OutDir)</OldOutDir>

      <OutDir>$(SolutionDir)</OutDir>

    </PropertyGroup>

  </Target>

 

  <Target Name="AfterTestConfiguration">

    <PropertyGroup>

     <OutDir>$(OldOutDir)</OutDir>

    </PropertyGroup>

  </Target>

Whether this is a good idea or not I’m not sure, but it does seem to work. Note that I put it back the way it was afterwards (using AfterTestConfiguration).

Moral

I think the story here is that using CustomizableOutDir is a complete pain in the arse, which ends up requiring considerable customisation of the rest of the build workflow. I don’t mind a prescriptive process per-se, but I do have a real issue with the ‘flat’ output directory structure that Team Build kicks out. But attempting to change it just seems to cause a heap more trouble than it’s worth.

Actually - as Martin Fowler said years ago - using XML as a build language is a really dumb idea in retrospect. Everyone says TeamCity’s pretty cool: might be time to take a look at that…

 

PS: If you’re trying to get your head around what happens where in Team Build (aren’t we all) there’s a great Team Build Target Map over at the Accentient blog

PS: I notice on Aaron Hallberg’s blog there’s a much simpler approach if you just want to separate per-solution output directory structures, which may not suffer the same problems.

Thursday, May 06, 2010

WinDbg Pain Points

Previously I talked about PowerDbg, what an awesome idea it was, but how it lacked some things. Well I spoke to the author, Roberto[1], who asked me to put my code where my mouth was, and now I am working with him on the next version.

So… if there’s anything particularly painful that you do in WinDBG now is the time to shout. You can comment on this blog if you like, but better would be to raise a ‘proposed feature’ on the Codeplex site itself.

A good example would be just how hard it is to work with a .Net Dictionary in WinDBG (except PowerDbg already handles that, and even better in the new version). Anything where you want a slightly ‘higher level’ view of the raw SOS data.

 

[1] Yes, that Roberto.

Tuesday, May 04, 2010

PowerShell 2 Breaking Change When Shelling Out

Whilst PowerShell 2 is by-and-large backwards compatible, I’ve discovered at least one breaking change that appears to be undocumented: the behaviour of argument parsing when calling another executable seems to have changed.

Previous behaviour:

clip_image002

PowerShell has effectively parsed the argument as if it were calling a PowerShell script: splitting it into two parts along the colon, and passing the second part ‘intact’ because it was quote wrapped.

New behaviour in v2:

image

PowerShell has treated the arguments as completely opaque and passed them to the exe using ‘normal’ command line parsing semantics (split on spaces etc…). It has not split the argument along the colon (which was the breaking change for us). In the second case, because the argument didn’t start with a quote (it starts with ‘-test’) the argument is broken in half at the space.

I think this is a good change, in that PowerShell shouldn’t make assumptions about how the exe you are calling likes it’s parameters (I got badly burnt that way trying to call an SSIS package). But it’s certainly one to watch out for.

 

PS: Not sure at all about this behaviour, which is the same in both v1 and v2:

image

Surely the fact you pass the argument as a string variable indicates you want it as one argument. Surely.

Popular Posts