Tuesday, December 28, 2010

WiX 3.5 in Visual Studio 2010 undefined preprocessor variable when solution folders used

I ran into a problem with the WiX 3.5 installer in Visual Studio 2010 when trying to add a reference to a project in a solution folder. The folder structure looked like this:

  • Client
    • WiXProject
      • References
        • Common _Common\Common_
  • Common
    • Common
The installer built fine when I set Harvest to True, but, since I wanted more control over the installer, I wanted to manually edit the wxs file like this:

<file diskid="1" id="Common" name="$(var.Common.TargetFileName)" source="$(var.Common.TargetPath)">

Unfortunately, Votive (the WiX integration with Visual Studio) does not seem to correctly handle references to projects in solution folders. The workaround I used was to unload the WiX project and edit the line as highlighted:

    
      Common _Common\Common_
      {89f6f5f2-5aeb-4501-9f4f-9073d7dedd4c}
      True
      True
      Binaries;Content;Satellites
      INSTALLLOCATION
    

    
      Common
      {89f6f5f2-5aeb-4501-9f4f-9073d7dedd4c}
      True
      True
      Binaries;Content;Satellites
      INSTALLLOCATION
    

When I reloaded the project, my wxs file worked as originally configured because the variable var.Common.TargetFileName was now defined.

Monday, December 20, 2010

Virtual Server 2005 R2 minimum host user permissions

This page on MSDN lists the following permissions required for a user to run a virtual machine:

  • On the .vmc file: Read Data, Write Data and Execute File
  • On the .vhd file: Read Data, Read Attributes, Read Extended Attributes, and Write Data
  • On the .vnc file if a virtual machine is connected to a virtual network: Execute File, Read Data, Read Attributes and Read Permissions
  • On the folder containing the .vmc file, for a virtual machine to have the ability to save state: List Folder and Write/Create File

Unfortunately, this list is not complete. They also need:
  • On the .vmc file: Read Permissions

The error you may see when you attempt to start a VM configured according to the MSDN page is:

The following error occurred:
The virtual machine could not be started. The virtual machine could not be started. Access was denied.


Using these permissions, you can create a local user who belongs to no groups and only has the permissions provided above - security through least privilege.

Sunday, December 19, 2010

Installing Debian 5 (Lenny) on Microsoft Virtual Server 2005 R2 SP1

If you run into a kernel panic installing Debian 5 (Lenny) on Microsoft Virtual Server 2005 R2 SP1 (32 bit host and client), try this:
  1. Launch the Debian CD.
  2. Press TAB on the Install option to edit the command line.
  3. Change
    vga=normal
    to
    vga=791
  4. Add the following:
    noapic nolapic noreplace-paravirt
  5. Install as normal.

Problem selecting drop down options in MS Virtual Server 2005 R2

I ran into problems when trying to create a new virtual machine on Microsoft Virtual Server 2005 R2 SP1. Clicking on the drop-down lists (such as network selection) did not have any effect. This is how the lists appeared:




The problem turned out to be that I needed to turn on compatibility mode for the site in Internet Explorer 8. After doing that, this is how the drop-down list looked:

Thursday, December 16, 2010

Dynamic linking of shared libraries in Linux

To list the classes, functions, and methods exported by a shared library (.so), use this command:

nm -C --defined-only -g liblibrary.so

To view a list of shared libraries required by a program:

ldd program

Tested on Ubuntu 10.10. Note that the equivalent functionality in Windows would be provided by dumpbin.exe.

Boost serial ports and new C++0x (C++1x) features

I recently spent some time writing my first small application on Linux (Ubuntu 10.10 using GCC 4.5 and the Boost libraries). The plan is to try writing some cross-platform, portable C++, while trying out the new C++0x features that have been implemented in GCC 4.5.

This application uses the asio (asynchronous I/O) features in the Boost libraries along with the Boost serial_port implementation to read and display input from a serial port (e.g. GPS NMEA data). I also used experimental C++0x threading libraries and lambdas and tried the Boost implementation of the observer pattern - sockets and signals. I have yet to test this code on any other platform.

main.cpp

#include "headers.h"
#include "SerialPort.h"
using namespace std;
using namespace boost::asio;

int main()
{
        //allow inter-mixing of wcout and cout calls (apparently non-standard)
        ios::sync_with_stdio(false);

        string portName = "/dev/ttyUSB1";

        io_service ioService;
        io_service::work work(ioService);
        thread ioThread([&ioService] () { ioService.run(); });

        SerialPort port(portName, 4800, ioService);
        port.LineReceived.connect([] (std::vector<char> const & line)
            {
                cout << &line[0] << endl;
            });

        wcout << L"Listening on port: " << endl;
        cout << portName << endl;
        wcout << L"Press enter to stop listening..." << endl;
        wstring result;
        getline(wcin, result);
        wcout << L"Exiting..." << endl;

        ioService.stop();
        ioThread.join();
}

headers.h

Separated for precompilation.
#include <boost/asio.hpp>
#include <boost/signal.hpp>
#include <iostream>
#include <vector>
#include <thread>
#include <functional>

SerialPort.h

#ifndef SERIALPORT_H
#define SERIALPORT_H

class SerialPort
{
public:
    SerialPort(std::string const & portName, int portSpeed, boost::asio::io_service & ioService);

    boost::signal<void(std::vector<char> const &)> LineReceived;

private:
    void OnBytesRead(boost::system::error_code const &error, size_t bytesReceived);
    void BeginListening();

    std::vector<char> _readBuffer;
    std::vector<char> _currentLine;
    boost::asio::serial_port _port;
};

#endif // SERIALPORT_H

SerialPort.cpp

#include "headers.h"
#include "SerialPort.h"
using namespace std;
using namespace boost::asio;

SerialPort::SerialPort(string const & portName, int const portSpeed, io_service & ioService)
    : _readBuffer(1000),
      _port(ioService, portName)

{
    _port.set_option(serial_port_base::baud_rate(portSpeed));

    BeginListening();
}

void SerialPort::BeginListening()
{
    _port.async_read_some(buffer(&_readBuffer[0], _readBuffer.size()),
        [this](boost::system::error_code const &error, size_t bytesReceived)
        {
            this->OnBytesRead(error, bytesReceived);
        });
}

void SerialPort::OnBytesRead(boost::system::error_code const &error, size_t bytesReceived)
{
    if(error)
    {
        return;
    }

    for(size_t i = 0; i != bytesReceived; ++i)
    {
        char currentChar = _readBuffer[i];
        switch(currentChar)
        {
        case '\r':
            break;
        case '\n':
            LineReceived(_currentLine);
            _currentLine.clear();
            break;
        default:
            _currentLine.push_back(currentChar);
        }
    }

    BeginListening();
}

Wednesday, November 24, 2010

What exceptions can a WCF channel throw?

It seems that expected exceptions from a WCF channel include:

  • TimeoutException
  • CommunicationException - FaultException, FaultException, EndpointNotFoundException etc.

MSDN describes the exceptions that are caused by communication errors.

Also from MSDN:

When implementing custom channels and binding elements, it is strongly recommended that your components throw only System.TimeoutException or CommunicationException-derived objects. In the case where your components throw a recoverable exception that is specific to the component, wrap that exception inside a CommunicationException object.

MSDN also describes how to specify and handle faults in WCF contracts and services.

Saturday, November 20, 2010

Checking your credit rating in New Zealand for free

Check your own credit rating details for free in New Zealand at two major credit rating companies:


Charges only apply to their 'express' services.

Friday, November 19, 2010

PowerShell Profile

Some handy functions I put into my PowerShell profile.

#Change background colour of window if PowerShell is launched "As Administrator" under UAC
& {
    $wid=[System.Security.Principal.WindowsIdentity]::GetCurrent()
    $prp=new-object System.Security.Principal.WindowsPrincipal($wid)
    $adm=[System.Security.Principal.WindowsBuiltInRole]::Administrator
    $IsAdmin=$prp.IsInRole($adm)
    if ($IsAdmin)
    {
        (get-host).UI.RawUI.Backgroundcolor="DarkRed"
        clear-host
    }
}

#Create an alias 'ed' to launch Visual Studio as your file editor
function Edit-WithDevenv([string]$Path)
{
    & devenv /edit $Path 
}
new-alias ed edit-withdevenv

MSBuild

Links to elements and tasks, including the community tasks.

Well known metadata.

Using ASP.NET authentication in Silverlight with RIA Services

The first step is to set up the database you wish to authenticate against (ignore this if you are using Windows authentication, which wouldn't apply for most websites).

If you are not using the default DB, add this to the configuration section in your web.config:

<connectionStrings>
    <clear/>
    <add name="LocalSqlServer" connectionString="data source=(local); Integrated Security=SSPI;Initial Catalog=ASPNET;" providerName="System.Data.SqlClient" />
</connectionStrings>

(Thanks to centricle.com for the html encoding utility.)

To add the default ASP.NET authentication tables to the database, use aspnet_regsql.

asp.net has a good introduction to setting up ASP.NET authentication.

This blog entry shows how to modify the silverlight business templates to use ASP.NET forms authentication with "stay logged in" feature.

RIA tid-bits

Server side:
DomainService (with [EnableClientAccess])

[ServiceOperation] for generic operations

[Query] or Get...(args); returning T, IEnumerable or IQueryable
Use HasSideEffects = true to send query as post.
[Insert] or Insert...(args)
[Update] or Update...(args)
[Delete] or Delete...(args)
Resolve is used for optimistic concurrency resolution.
[Custom] methods return void and take an entity as the first parameter but is not one of the above. They are change tracked etc.
[ServiceOperation] are more like web methods.

Entities may inherit from entity, but must have a key if used in an IEnumerable collection.

[Include] is used to link classes together, for example Job and JobNotes. This will ensure the code generator will copy JobNotes to the client project. This can also be used for data denormalisation on the Job class's metadata class:
[Include("NoteDateTime", "DateTime")]
public JobNotes JobNotes;
This will result in a new property on the Job class on the client called NoteDateTime and only serialise the DateTime of the job note, not the detail.

[MetadataType] can be used to specify another class whose attributes are merged with the main class. Attributes on properties in the metadata class are merged with those on the main class. This is useful for modifying the attributes on compiler generated code through partial classes.

Client side:
Perform linq operations to filter (if required) the query, using the query as IEnumerable, then use the DomainContext's Load methods to load the data asynchronously.

DataGrid / DataForm / FieldLabel:
[Bindable] specifies whether a property is bindable or not.
[Display(Name, Description)]

Validation:
[StringLength]
[Required]
[Range]
[RegularExpression]
[CustomValidation]
[DataType]
Custom validation attributes can be made by deriving from ValidationAttribute.

Authorisation:
[RequiresAuthentication]

Shared code:
Code file should be called xxxxx.shared.cs, then use [Shared].
Use [CustomValidation] for validation code (see this).

A useful application of shared code is to add a partial class that extends the functionality of a generated class, i.e. to add a new calculated property. This class will then be copied to the client and the calculated property will be in both client and server code.

More detail:
See this page.

PowerShell script to get a list of all assemblies required by a .NET executable

param ([string][parameter(mandatory=$true)]$path)

function GetReferencedAssemblies([reflection.assembly][parameter(mandatory=$true)]$top)
{
    $script:found += $top.Location

    $ref = $top.getreferencedassemblies() 
    $ref | % {
        $name = $_.name
        $loaded = $null
        try
        {
            $loaded = [reflection.assembly]::load($_) 
        }
        catch
        {
            $loaded = [reflection.assembly]::loadfrom((resolve-path ($name + '.dll')))
        }

        if($script:found -notcontains $loaded.Location -and -not $loaded.GlobalAssemblyCache)
        {
            GetReferencedAssemblies $loaded
        }
    }
}

$path = resolve-path $path -ErrorAction stop
pushd (split-path $path)
try
{
    $found = @()
    $top = [reflection.assembly]::loadfrom($path)
    GetReferencedAssemblies $top
    $found
}
finally
{
    popd
}

PowerShell script to get the IPv4 address of a server

Possible usage:
Get-HostIp servername | clip

function Get-HostIp([string][parameter(mandatory=$true)]$HostName)
{
 resolve-host $HostName | select -expandproperty addresslist -First 1 | select -ExpandProperty ipaddresstostring
}

Generate DB script using PowerShell

This is an example script that can be used to dump a SQL Server database schema into a creation script. The advantages of this method over using SQL Server Management Studio include:
  • Scriptable. Can be included in a build or commit script.
  • Repeatable. SQL Server Management Studio generated scripts vary from run to run, so it can be difficult to make comparisons with previous versions of the schema in source control.
  • Repeatable. Using the SQL Server Management Studio GUI to create scripts relies on everyone ticking the same boxes to generate consistent and correct DB scripts.
  • Configurable. This script ignores objects (e.g. tables and triggers) with names starting with 'test'.
<#
.SYNOPSIS
.NOTES
Author: 
#>

$root = resolve-path ((split-path -path $MyInvocation.MyCommand.Definition -Parent) + '\..\..');
$serverURL = 'SQL2005'
$databaseName = "DBToDump";
$scriptFile = "$root\Scripts\Create.sql"

#================== GetObjectsFromDB ===================
function GetObjectsFromDB(
[parameter(mandatory=$true)]$Database, 
[parameter(mandatory=$true)][string]$ObjectType)
{
    $objects = [Microsoft.SqlServer.Management.Smo.SqlSmoObject[]]($database.$ObjectType | Where-object {$_.IsSystemObject -ne $true -and $_.IsFixedRole -ne $true -and $_.Name -notmatch '^test' } );
    if($objects)
    {
        ,$objects
    }
    else
    {
        ,@()
    }
}
#=======================================================

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | out-null
$server = new-object Microsoft.SqlServer.Management.Smo.Server ($serverURL);
$server.SetDefaultInitFields([Microsoft.SqlServer.Management.SMO.StoredProcedure], "IsSystemObject")
$db = $server.Databases[$databaseName];

if(Test-Path $scriptFile)
{
    del $scriptFile
}

$scripter = new-object Microsoft.SqlServer.Management.Smo.Scripter ($server);
$options = $scripter.Options
$options.ScriptDrops = $false
$options.IncludeIfNotExists = $false
$options.ScriptData = $false
$options.NoCommandTerminator = $false
$options.FileName = $scriptFile
$options.SchemaQualify = $true
$options.ToFileOnly = $true
$options.AppendToFile = $true
$options.DriAllConstraints = $true
$options.Indexes = $true
$options.ClusteredIndexes = $true
$options.Statistics = $true
$options.IncludeDatabaseRoleMemberships = $true
$options.TargetServerVersion = [Microsoft.SqlServer.Management.Smo.SqlServerVersion]::Version90
$options.NoFileGroup = $true
$options.DriAll = $true

echo "Scripting database..."
$scripter.EnumScript($db)

#don't script collation for DB objects since it has been done for the database as a whole
$options.NoCollation = $true

#switch to newly created DB
"
USE [$databaseName]
GO
" | out-file -append $scriptFile -ErrorAction stop

$objects = GetObjectsFromDB $db "Schemas"
$objects += GetObjectsFromDB $db "Roles"
$objects += GetObjectsFromDB $db "Tables"
$objects += GetObjectsFromDB $db "UserDefinedFunctions"
$objects += GetObjectsFromDB $db "StoredProcedures"
$objects += GetObjectsFromDB $db "Views"

$scripter.EnumScript($objects)

echo "Done."

#set permissions (not sure how to script the ones I want without including test permissions)
"
GRANT EXECUTE ON SCHEMA::[app] TO [application] AS [dbo]
GO
GRANT SELECT ON SCHEMA::[cfg] TO [application] AS [dbo]
GO
GRANT SELECT ON SCHEMA::[cfg] TO [support] AS [dbo]
GO
GRANT SELECT ON SCHEMA::[dbo] TO [support] AS [dbo]
GO
GRANT UPDATE ON SCHEMA::[cfg] TO [support] AS [dbo]
GO
GRANT SELECT ON SCHEMA::[sup] TO [support] AS [dbo]
GO
GRANT VIEW DEFINITION ON SCHEMA::[sup] TO [support] AS [dbo]
GO
GRANT VIEW DEFINITION ON SCHEMA::[cfg] TO [support] AS [dbo]
GO
GRANT VIEW DEFINITION ON SCHEMA::[dbo] TO [support] AS [dbo]
GO
GRANT EXECUTE ON SCHEMA::[sup] TO [support] AS [dbo]
GO" | out-file -append $scriptFile -ErrorAction stop

Wednesday, November 17, 2010

Windows Software I can't live without


Honourable mention:

Visual Studio 2012:
  • Visual Studio 2012 Update 1 (should be downloaded automatically from within VS 2012)
  • ASP.NET and Web Tools 2012.2
  • ReSharper 7.1, if installed using these steps:
    1. Set VS keyboard shortcuts to C# and reset to defaults.
    2. Set R# keyboard shortcuts to Visual Studio style.
    3. Set The following R# options:
      • Code Editing -> C# -> Formatting Style -> Line Breaks and Wrapping -> Line Wrapping -> Wrap long lines: untick
      • Code Editing -> C# -> Formatting Style -> Other -> Modifiers -> Use explicit private modifier: untick
      • Code Editing -> C# -> Formatting Style -> Other -> Modifiers -> Use explicit internal modifier: untick
      • Code Editing -> C# -> Formatting Style -> Other -> Align Multiline Constructs -> Array, object and collection initializer: untick
      • Tools -> External Sources -> Navigation to Sources: tick all boxes
    4. Run the following code in the Package Manager Console:
      ($DTE.Commands | ? { $_.Name -eq 'ReSharper.ReSharper_DuplicateText' }).Bindings = @()
      ($DTE.Commands | ? { $_.Name -eq 'Edit.PasteParameterTip' }).Bindings = @()
      ($DTE.Commands | ? { $_.Name -eq 'ReSharper.ReSharper_IntroduceField' }).Bindings = @()
      

Tuesday, November 16, 2010

SSH client for .NET

I have been looking for a good, free, .NET SSH client. This SSH client seems to fit the bill.

I did, however, run into a problem where it appears that the state of the session is not preserved between calls. I will follow this up on the Codeplex page.

The following test fails:

[TestMethod]
public void ShouldMaintainSessionStateAcrossCommands()
{
    using (SshClient client = new SshClient("sssssss", "uuuuuuu", "ppppppp"))
    {
        client.Connect();

        client.RunCommand("cd /tmp");
        string result = client.RunCommand("pwd").Result;

        Assert.AreEqual("/tmp", result);
    }
}

EDIT: This is the issue I logged and the developer's response. It seems that this behaviour is "by design", which unfortunately means that there will not be a 'fix'.

The workaround would be to run all dependent commands separated by semicolons, although this is quite limiting in some situations.

Monday, November 15, 2010

Uploading a file using FTP and the WebClient

Note: more detailed documentation for the .NET 4.0 explains the reason for requiring the additional slash (/). See the remarks section for the FtpWebRequest class. If you are using .NET 4.0, this class is probably a better bet.

I ran into some trouble uploading a file using the System.Net.WebClient. Looking at examples in the web, it seemed quite straightforward, but I found that I needed to include an additional forward slash in order to get the transfer to work correctly.

At first, I struggled to upload a file with this call to my WebClient instance:

client.UploadFile("ftp://sssssss/folder/folder/folder/t.txt", @"c:\temp\t.txt");

I was able to download a file in that location with Internet Explorer using the URI above, but not upload to it using the WebClient.

This dump from Wireshark illustrates the problem (note line 14), which seems to be a bug in the WebClient to me:

220 sssssss FTP server (Version 1.1.214.4(PHNE_38458) Tue Jul 29 07:36:52 GMT 2008) ready.
USER uuuuuuu
331 Password required for uuuuuuu.
PASS ppppppp
230 User uuuuuuulogged in.
OPTS utf8 on
500 'OPTS utf8 on': command not understood.
PWD
257 "/home/fld/uuuuuuu" is current directory.
TYPE I
200 Type set to I.
PASV
227 Entering Passive Mode (xx,xx,xx,xx,xx,xx)
STOR folder/folder/folder/t.txt
553 Could not determine cwdir: No such file or directory.
221 You could at least say goodbye.

Noticing that the STOR command was providing a relative path (not starting with /), I assume that the server was trying to save the file into the current folder i.e. /home/fld/uuuuuuu/folder/folder/folder/t.txt. To test this theory, I added a slash at the beginning ot the path:

client.UploadFile("ftp://sssssss//folder/folder/folder/t.txt", @"c:\temp\t.txt");

I am not sure if this is a valid URI, but it seems to work with the WebClient, although I am not sure why the RETR command (line 19) is executed as in the following Wireshark dump:

220 sssssss FTP server (Version 1.1.214.4(PHNE_38458) Tue Jul 29 07:36:52 GMT 2008) ready.
USER uuuuuuu
331 Password required for uuuuuuu.
PASS ppppppp
230 User uuuuuuu logged in.
OPTS utf8 on
500 'OPTS utf8 on': command not understood.
PWD
257 "/home/fld/uuuuuuu" is current directory.
TYPE I
200 Type set to I.
PASV
227 Entering Passive Mode (xx,xx,xx,xx,xx,xx)
STOR /folder/folder/folder/t.txt
150 Opening BINARY mode data connection for /folder/folder/folder/t.txt.
226 Transfer complete.
PASV
227 Entering Passive Mode (xx,xx,xx,xx,xx,xx)
RETR folder/folder/folder/t.txt
550 folder/folder/folder/t.txt: No such file or directory.
221 You could at least say goodbye.


This is the final code that seems to work:

        public static void SendFile(string sourcePath, string server, string userName, string password, string remoteFolder, string remoteFileName)
        {
            using (WebClient client = new WebClient())
            {
                string dest = string.Format(CultureInfo.InvariantCulture, "ftp://{0}/{1}/{2}", server, remoteFolder, remoteFileName);
                client.Credentials = new NetworkCredential(userName, password);
                client.Proxy = null;
                client.UploadFile(dest, sourcePath);
            }
        }

And the corresponding integration test:

        [TestMethod]
        public void ShouldSubmitFileToFtpServer()
        {
            Guid uniqueId = Guid.NewGuid();

            string tempFile = Path.Combine(Path.GetTempPath(), "FtpTestFile.txt");
            File.WriteAllText(tempFile, "Test file - safe to delete. " + uniqueId.ToString());

            string server = "sssssss";
            string userName = "uuuuuuu";
            string password = "ppppppp";
            string folder = "/folder/folder/folder";
            string fileName = "t.txt";
            Ftp.SendFile(tempFile, server, userName, password, folder, fileName);

            string tempFileDown = tempFile + ".down";

            if(File.Exists(tempFileDown)) File.Delete(tempFileDown);

            using (WebClient client = new WebClient())
            {
                client.Credentials = new NetworkCredential(userName, password);
                string ftpLink = String.Format(CultureInfo.InvariantCulture, "ftp://{0}/{1}/{2}", server, folder, fileName);
                client.CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore);
                client.DownloadFile(ftpLink, tempFileDown);
            }

            string content = File.ReadAllText(tempFileDown);

            Assert.IsTrue(content.Contains(uniqueId.ToString()));
        }

Thursday, November 11, 2010

Example PowerShell header

This is a good template header that I use for new PowerShell scripts:

<#
.SYNOPSIS
    This is what the script does.
.NOTES
    Author: Me
.PARAMETER AParameter
    A parameter.
.PARAMETER ASwitch
    A switch.
#>

$ErrorActionPreference = 'Stop'
Set-StrictMode -Version 3

param(
    [parameter(mandatory)][string]$AParameter, 
    [switch]$ASwitch)

$scriptFolder = (split-path -path $MyInvocation.MyCommand.Definition -Parent)

Friday, November 5, 2010

Transforming an XML file with an XSLT in PowerShell

This code will transform an XML file with an XSLT file and save the resulting file to disk:

$xslt = new-object system.xml.xsl.xslcompiledtransform
$xslt.load('transform.xslt')
$xslt.Transform('input.xml', 'output.xml')

Wednesday, November 3, 2010

Complex work item queries in TFS

I recently wanted to create a work item query that showed all my work items that are either not closed or I had modified recently. This query provides a useful list of work items for associating with a check-in.

I wanted the query to show:
AssignedTo = @Me AND (State <> Closed OR (State = Closed AND ChangedDate > @Today - 7))

To do this, I needed to use multiple levels of the Group Clauses feature, which is available by selecting more than one clause and right clicking on one of the selected clauses.

The result is below:

Friday, October 29, 2010

Executing a PowerShell script from TFS 2010 workflow

  1. Add an InvokeProcess activity to the workflow.
  2. Set the DisplayName property to something useful for logging and debugging.
  3. Set the FileName property to "powershell.exe"
  4. Set the Arguments like this:
    "-file """ + SourcesDirectory + "\Scripts\SetAssemblyVersions.ps1"" " + MajorVersionNumber.ToString() + " " + MinorVersionNumber.ToString() + " " + BuildDetail.SourceGetVersion.Substring(1) + " " + BuildDetail.BuildNumber.Substring(BuildDetail.BuildNumber.LastIndexOf(".") + 1)
  5. Give names to the standard output and error output streams.
  6. Add a WriteBuildMessage activity under the Handle Standard Output field and set its Message property to the standard output stream defined above.
  7. Add a WriteBuildError activity under the Handle Error Output field and set its Message property to the error output stream defined above.

Thursday, October 28, 2010

Quotes I like

Give me six hours to chop down a tree and I will spend the first four sharpening the axe.
-- Abraham Lincoln

If you always put limit on everything you do, physical or anything else, it will spread into your work and into your life. There are no limits. There are only plateaus, and you must not stay there, you must go beyond them.
-- Bruce Lee

If I’d asked people what they wanted, they would have said a faster horse.
-- Henry Ford, car guy

Yesterday I tried to cut my steak with a spoon and that goddam spoon sucked-ass. Why the hell would anybody ever use a spoon for anything? They are completely useless!
-- Jason

I think that emphasizing heroics in any form usually does more harm than good.
-- Steve McConnell

Setting up FitNesse for .NET with SliM

Basic steps for setting up FitNesse for .NET with the wiki stored under source control. Review all code that you copy and paste from this page because it may need to be modified for your situation.

  1. Create a simple fixture:
    public class IsFitNesseCorrectlySetup
    {
        public int Value { get; set; }
    
        public int GetValueDoubled()
        {
            return Value * 2;
        }
    }
    
  2. Download FitNesse and SliM, and save these into separate folders under your third party folder in source control (everything here is presumed to be under source control).
  3. Create this .cmd file for testers to use (presumes TFS; will need to be modified for other source control systems):
    @echo off
    setlocal
    "%VS100COMNTOOLS%\..\IDE\TF.exe" get "%~dp0.." -r
    "%VS100COMNTOOLS%\..\IDE\TF.exe" checkout "%~dp0FitNesseRoot" -r
    C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe "%~dp0..\Solution\Solution.sln" /p:configuration=release
    set FitNessePort=8084
    start /min /d "%~dp0..\ThirdParty\FitNesse" java -jar fitnesse.jar -p %FitNessePort% -d "%~dp0." -r FitNesseRoot
    start http://localhost:%FitNessePort%/
    endlocal
  4. Launch FitNesse and add the following to the root page (modifying paths to match your folder structure):
    !*****> Configuration
    !define TEST_SYSTEM {slim}
    !path .dll
    !define COMMAND_PATTERN {%m -r fitSharp.Slim.Service.Runner,..\..\ThirdParty\FitSharp\fitsharp.dll %p}
    !define TEST_RUNNER {..\..\ThirdParty\FitSharp\Runner.exe}
    *****!
  5. Add a normal page (not a test page) called SetUp at the top level of your suite, and put the following in it to let FitNesse know which namespaces to find your fixtures in:
    !|import|
    |Your Fixture DLL namespace|
  6. Create a test page with this test:
    !|Is FitNesse correctly set up|
    |Value   |Get value doubled?  |
    |2       |4                   |
    |23      |46                  |
    |100     |200                 |
    |200     |399<_<401           |
    Run the test, which should pass.
Note that these files in the FitNesse wiki should not be checked in to source control:
  • *.zip
  • ErrorLogs\**
  • files\testResults\**
  • RecentChanges\**

Tuesday, October 19, 2010

Invalid code coverage item error in MSTest

I ran into the following running unit tests after a build under TFS 2010:

Invalid code coverage item: The pdb file name must contain at least one character.

I had modified the .testsettings file to use relative paths instead of absolute paths, but the build was failing with the above error.

The solution was to edit the .testsettings file to add a pdbFile attribute:

<CodeCoverageItem binaryFile="..\Utilities\%outdir%\Utilities.dll" pdbFile="..\Utilities\%outdir%\Utilities.pdb" instrumentInPlace="true" />

Continuous integration

This is what I like to run for continuous integration builds:
  1. Set version numbers in all assemblies.
  2. The release build.
  3. Code analysis (build breaker).
  4. Unit tests (build breaker).
  5. Integration tests (build stability).
  6. FitNesse tests (build stability).

Outputs I like to collect are:
  • Build outputs, including PDBs, ideally in a symbol server.
  • Code coverage percentage and details.
  • Test results.

Wednesday, October 13, 2010

Setting up code analysis in Visual Studio

Code Analysis Rule Files

Copy these files to an appropriate location in the source tree:
For test code:
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="Test Code" Description="Rules for unit and integration test assemblies." ToolsVersion="11.0">
  <IncludeAll Action="Error" />
  <Rules AnalyzerId="Microsoft.Analyzers.ManagedCodeAnalysis" RuleNamespace="Microsoft.Rules.Managed">
    <Rule Id="CA1004" Action="None" />
    <Rule Id="CA1014" Action="None" />
    <Rule Id="CA1020" Action="None" />
    <Rule Id="CA1024" Action="None" />
    <Rule Id="CA1026" Action="None" />
    <Rule Id="CA1031" Action="None" />
    <Rule Id="CA1062" Action="None" />
    <Rule Id="CA1300" Action="None" />
    <Rule Id="CA1303" Action="None" />
    <Rule Id="CA1502" Action="None" />
    <Rule Id="CA1506" Action="None" />
    <Rule Id="CA1702" Action="None" />
    <Rule Id="CA1707" Action="None" />
    <Rule Id="CA1709" Action="None" />
    <Rule Id="CA1822" Action="None" />
    <Rule Id="CA2204" Action="None" />
    <Rule Id="CA2210" Action="None" />
  </Rules>
</RuleSet>
For production code:
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="Production Code" Description="Rules for production code." ToolsVersion="11.0">
  <IncludeAll Action="Error" />
  <Rules AnalyzerId="Microsoft.Analyzers.ManagedCodeAnalysis" RuleNamespace="Microsoft.Rules.Managed">
    <Rule Id="CA1004" Action="None" />
    <Rule Id="CA1020" Action="None" />
    <Rule Id="CA1024" Action="None" />
    <Rule Id="CA1026" Action="None" />
    <Rule Id="CA1303" Action="None" />
    <Rule Id="CA1502" Action="None" />
    <Rule Id="CA1506" Action="None" />
    <Rule Id="CA1822" Action="None" />
    <Rule Id="CA2204" Action="None" />
    <Rule Id="CA2210" Action="None" />
  </Rules>
</RuleSet>

Language

I am not aware of a GUI that allows setting the language for Visual Studio code analysis.

To do this manually, add the following line to your .csproj files under the main <PropertyGroup> tag:

<CodeAnalysisCulture>en-NZ</CodeAnalysisCulture>

This setting is obviously for New Zealand English. Consult this table for the appropriate locale ID.

Custom Dictionary

Set up a custom dictionary file called CustomDictionary.xml and add a link to it in one of your projects. Set the build action (in the properties page) to CodeAnalysisDictionary. To duplicate this into other projects in the same solution, just drag into each of those solutions. I use the following as a default:
<Dictionary>
  <Words>
    <Unrecognized>
      <Word></Word>
    </Unrecognized>
    <Recognized>
      <Word>Mvc</Word>
      <Word>Serialise</Word>
      <Word>Serialisation</Word>
      <Word>Serialiser</Word>
      <Word>Deserialise</Word>
      <Word>Deserialised</Word>
      <Word>Deserialisation</Word>
      <Word>Nesse</Word>  <!--From FitNesse-->
    </Recognized>
    <Deprecated>
      <Term PreferredAlternate=""></Term>
    </Deprecated>
    <Compound>
      <Term CompoundAlternate=""></Term>
    </Compound>
    <DiscreteExceptions>
      <Term></Term>
    </DiscreteExceptions>
  </Words>
  <Acronyms>
  </Acronyms>
</Dictionary>

Project Configuration

In each project's property pages under the Code Analysis tab, set the rule set to either the test or production set, and enable the code analysis for release builds only. Running code analysis slows down the build and may not be suitable for debug builds.

TFS

In your continuous integration build definition, set code analysis to Always.

Friday, September 10, 2010

Flattening an AD group hierarchy

Sometimes it can be difficult to find all the members of an active directory group when there are multiple child or sub groups.

To flatten the hierarchy, use this command:
dsquery group -limit 0 | select-string group_to_find | dsget group -members -expand

Friday, August 6, 2010

Calculating prices after GST changes

There has been some dodgy maths in the New Zealand media recently around how much things will cost after the GST increases in October. The rate will be increasing from 12.5% to 15%, so some media are simply adding 2.5% on top of the price. Unfortunately, the calculation is not that simple. First, you need to remove the current GST portion, and then calculate the new price with the new GST rate:



Unfortunately, the calculation is not easy to do in your head: 46 × originalprice / 45. Another way of looking at it is to add 1/45 of the current price, or ~2.22%

Friday, July 16, 2010

Overriding protected members using Moq and/or RhinoMocks

Sometimes I want to override a protected method on an internal class using a mocking framework and make verifications against calls to that method. This problem also occurs when trying to mock an internal interface in the assembly under test.

When doing this with Moq or RhinoMocks (both of which use the same proxy generator), I got the following error:

"Castle.DynamicProxy.Generators.GeneratorException: Type is not public, so a proxy cannot be generated."

The solution is to publish the internals of the assembly under test to the appropriate assembly:

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2," +
    "PublicKey=00240000048000009400000006020000002400005" +
    "25341310004000001000100c547cac37abd99c8db225ef2f6c8" +
    "a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7" +
    "852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0" +
    "a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15" +
    "605093924cceaf74c4861eff62abf69b9291ed0a340e113be11" +
    "e6a7d3113e92484cf7045cc7")]

Tuesday, July 13, 2010

Relative paths in .testsettings file

To configure relative code coverage paths in the .testsettings file, you will need to manually edit the xml file. First configure your coverage DLLs using the UI, then open the .testsettings file in a text editor, or in VS using the VS text editor.

Edit the absolute paths to be relative to the location of your testsettings file, and use the %outdir% macro instead of bin\Debug:
..\..\Utilities\%outdir%\Utilities.dll

Sunday, June 20, 2010

Extracting files in PowerShell without third party components

Sometimes it is not acceptable to install or use third party components such as 7-zip or the PowerShell Community Extensions onto machines (particularly because they are not digitally signed). This script will extract files using the shell API:

param(
[parameter(mandatory=$true)][string]$SourceFile,
[parameter(mandatory=$true)][string]$DestinationFolder)

if(-not (test-path $DestinationFolder))
{
    md $DestinationFolder | Out-Null
}

$absoluteSource = resolve-path $SourceFile | select -ExpandProperty path
$absoluteDestination = resolve-path $DestinationFolder | select -ExpandProperty path

$app = new-object -ComObject Shell.Application
$archive = $app.Namespace($absoluteSource).Items()
$dest = $app.Namespace($absoluteDestination)
$dest.CopyHere($archive)

Thursday, May 20, 2010

PowerShell and slash-colon parameters

PowerShell plays around with the quotes in parameters when part of the parameter is quoted like this:

/param:"quoted path"

This gets passed to the application as:
"/param:quoted path"

The only workaround I have found works like this:
$cmd = "& `"application`" /p:`"path`"; `$result = `$?"
Invoke-expression $cmd
if(!$result)
{
    throw "Application failed."
}

Monday, May 3, 2010

Running MSTest in Parallel

This blog describes how to execute tests in parallel in MSTest.

Writing Debug (-Verbose) Output in PowerShell

To write output in PowerShell that is only displayed when the -Verbose switch is given, use the following attribute in your script:
[CmdletBinding]

Then use write-verbose.

This makes the function an Advanced Function.

Sunday, May 2, 2010

Highlight PowerShell in red when running as Administrator

If you have the PowerShell Community Extensions installed, you can load your profile for editing by running notepad $profile or ep.

Paste the code from this blog into your profile:
& {
    $wid=[System.Security.Principal.WindowsIdentity]::GetCurrent()
    $prp=new-object System.Security.Principal.WindowsPrincipal($wid)
    $adm=[System.Security.Principal.WindowsBuiltInRole]::Administrator
    $IsAdmin=$prp.IsInRole($adm)
    if ($IsAdmin)
    {
        (get-host).UI.RawUI.Backgroundcolor="DarkRed"
        clear-host
    }
}

If you are running all users as standard users (which you should really be doing, see why here), there is no need to use this script. Simply put the following code into the Administrator profile:
(get-host).UI.RawUI.Backgroundcolor="DarkRed"
clear-host

Friday, April 30, 2010

Windows Event Log Message Text File

It took me a while to find the format of the message text file, but here it is.

Don't forget that you need a newline after the last full-stop in the file.

Thursday, April 29, 2010

ETW in .NET

After searching for a while, I found the classes for using Event Tracing for Windows in .NET. They are in the System.Diagnostics.Eventing namespace.

Note that these classes only work on Vista and Server 2008 (and newer).

Wednesday, April 28, 2010

Differences between csc (devenv) and msbuild

The drive letter in the stack frame text is lower case when built using msbuild, and upper case when build in VS 2008.

Monday, April 26, 2010

WCF Tools

WCF test client: WcfTestClient.exe.

Trace viewer: SvcTraceViewer.exe.

Friday, April 23, 2010

Contract first WCF tips

Generate types from xsd using WSCF Blue with options set to correct capitalisation.

On the interface:
Apply the ServiceContractAttribute with the service namespace.
Apply the XmlSerializerFormat(SupportsFaults = true) attribute.

On the interface's operation:
Apply FaultContractAttribute.
Apply OperationContractAttribute.

On the service class:
Apply any behaviour attributes, such as for error handling.
Apply the ServiceBehaviourAttribute, and set ConcurrencyMode = ConcurrencyMode.Multiple, IncludeExceptionDetailInFaults = false.

The operation should take a type such as:

[MessageContract(IsWrapped = false)]
public class Input
{
    [MessageHeader(Name = "headerData")]
    public Header Header { get; set; }

    [MessageBodyMember(Name = "inputData")]
    public Body Body { get; set; }
}

The response must be similar:

[MessageContract(IsWrapped = false)]
public class Response
{
    [MessageHeader(Name = "headerData")]
    public Header Header { get; set; }

    [MessageBodyMember(Name = "responseData")]
    public Body Body { get; set; }
}

Thursday, April 22, 2010

Preventing method inlining in c#

I sometimes want to prevent inlining of methods byt the JIT in C#. Usually this is because I need the call stack to be preserved, for example when using Assembly.GetCallingAssembly.

This is the attribute:
[MethodImpl(MethodImplOptions.NoInlining)]

Wednesday, April 21, 2010

Detailed performance summary in MSBuild

Use the /ds switch to get a summary of build nodes and the projects they built, with timings.

Sunday, April 18, 2010

Different types of SafeHandle

I ran into the following error:
"Cannot marshal 'return value': Returned SafeHandles cannot be abstract."

The Microsoft.Win32.SafeHandles namespace has several different handle types.

Thursday, April 8, 2010

Change to folder that PowerShell script is located

To change to the folder or directory that the executing PowerShell script is located:

pushd (Split-Path -Path $MyInvocation.MyCommand.Definition -Parent)

Alternatively:

$scriptFolder = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent

Note that $PSScriptRoot is preferable for PowerShell 3.0.

Saturday, March 20, 2010

Monday, March 8, 2010

Reserving HTTP namespace for use by self-hosted WCF application

I ran into the following error while creating a WCF application that is not hosted in IIS:

HTTP could not register URL http://+:8080/Logging/. Your process does not have access rights to this namespace (see http://go.microsoft.com/fwlink/?LinkId=70353 for details).

The solution on Vista is to reserve the namespace for the user that wants to bind to this URI, which must be done as an administrator:

netsh http add urlacl url={url} user={user\domain}

See MSDN for more detail, and don't forget that you will need to configure your firewall if you want this address to be externally visible.

Saturday, March 6, 2010

Programming job trends

This job search site provides some interesting trend information:

Programming Languages

cobol, java, perl, C++, C#, visual basic,delphi Job Trends graph



cobol, java, perl, C++, C#, visual basic,delphi Job Trends graph


Platforms

linux,windows Job Trends graph



linux,windows Job Trends graph


Platforms with C++ and C#

linux AND C++, windows AND c++,linux AND C#,windows AND C# Job Trends graph



linux AND C++, windows AND c++,linux AND C#,windows AND C# Job Trends graph


Databases

SQL Server,Informix,DB2,Oracle,Sybase,MySQL,Postgres Job Trends graph



SQL Server,Informix,DB2,Oracle,Sybase,MySQL,Postgres Job Trends graph

Tuesday, February 23, 2010

Smallest C++ windowed application

Interesting to see this is the smallest windowed Windows application:

#include <windows.h> 

LRESULT WINAPI WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); 

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShow)
{
    MSG msg;

    WNDCLASSEX wc = {sizeof(WNDCLASSEX), CS_VREDRAW|CS_HREDRAW|CS_OWNDC, 
    WndProc, 0, 0, hInstance, NULL, NULL, (HBRUSH)(COLOR_WINDOW+1), 
    NULL, L"DX9_TUTORIAL1_CLASS", NULL}; 

    RegisterClassEx(&wc);

    HWND hMainWnd = CreateWindow(L"DX9_TUTORIAL1_CLASS", 
    L"DirectX 9 Bare Bones Tutorial 1", 
    WS_OVERLAPPEDWINDOW, 100, 100, 300, 300, 
    NULL, NULL, hInstance, NULL);
    ShowWindow(hMainWnd, nShow);
    UpdateWindow(hMainWnd);

    while(GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return(0);
} 

LRESULT WINAPI WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_DESTROY:
        PostQuitMessage(0);
        return(0);
    }

    return(DefWindowProc(hwnd, msg, wParam, lParam));
}

Thursday, February 18, 2010

Using minidumps in .NET 4.0

.NET 4.0 provides for post mortem debugging of minudumps - but only if they include a full memory dump (which makes them not so 'mini' any more). This post list tips for using these dumps.

ProcDump can be used to make dumps in various scenarios, including high CPU usage, unhandled exception, etc.

Tuesday, February 16, 2010

Setting user environment variables for non-administrators with UAC

It is not possible to use the System Properties to set the environment variables for a non-administrative user. Launching this dialog requires elevation, and this means running as Administrator.

To correctly set the variables using a GUI, use User Accounts in the control panel.

To use the command line, use setx.

Wednesday, February 3, 2010

Converting SecureString to String

This blog shows the correct way to convert a SecureString to a String for the many APIs that require it.

Copied here in case the link breaks sometime in the future:
public static string ConvertToUnsecureString(this SecureString securePassword)
{
    if (securePassword == null)
        throw new ArgumentNullException("securePassword");

    IntPtr unmanagedString = IntPtr.Zero;
    try
    {
        unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(securePassword);
        return Marshal.PtrToStringUni(unmanagedString);
    }
    finally
    {
        Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
    }
}

public static SecureString ConvertToSecureString(this string password)
{
    if (password == null)
        throw new ArgumentNullException("password");

    unsafe
    {
        fixed (char* passwordChars = password)
        {
            var securePassword = new SecureString(passwordChars, password.Length);
            securePassword.MakeReadOnly();
            return securePassword;
        }
    }
}

Tuesday, February 2, 2010

Trying a new keyboard layout

I am trying the Colemak keyboard layout because it seems to be a lot smarter than qwerty. Requirements of keyboards have moved on since the days of typrewriters...

Colemak seems to be a good candidate because it minimises the number of changed keys to make it easier to switch between the ubiquitous qwerty and Colemak.

To test my current speeds as a benchmark, I used an online speed test.

On 2 February, 2010, My qwerty speed was 61 WPM, and my Colemak speed was 9 WPM, while using the on-screen keyboard as a guide.

On 3 February, 2010, my Colemak speed was 10 WPM, without looking at the keys.

On 7 February, 2010, my Colemak speed was 15 WPM.

On 8 February, 2010, my Colemak speed was 19 WPM (with one mistake: missing the second 'e' of Hernecastle).

Monday, February 1, 2010

Preserving the complete stack trace when rethrowing an exception

Even throw; loses the top level of the stack trace. Use this 'hack' to work around the problem:

static void PreserveStackTrace(Exception exception)
{
    MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace",
        BindingFlags.Instance | BindingFlags.NonPublic);
    preserveStackTrace.Invoke(exception, null);
}

(from here)

Monday, January 25, 2010

Web service / WCF testing tool

wcftestclient is a simple tool for manual testing of web and WCF services. It is installed with Visual Studio.

Monday, January 18, 2010

Broken Silverlight breakpoints

When debugging a Silverlight application in Visual Studio, sometimes breakpoints will not be set due to a symbol load error. This appears to be caused by the xap file being cached. In my case, the following PowerShell command fixed the problem:

dir -fo -r "~\AppData\Local\Microsoft\Windows\Temporary Internet Files" -inc *.xap | % {del $_}