Damian Hickey

Mostly software and .NET related. Mostly.

Re-namespacing an assembly with Mono.Cecil and powershell

Recently (and regularly) encountered a diamond dependency problem where I had library 1 that depended on version A of an assembly and library 2 that depends on same assembly but version 2. This resulted in a clash at the application level. Keeping both libriaries up-to-date with latest version of the assembly was attempted but the updates were always out of sync. The way the assemblies were being consumed was such that types were exposed through the libriaries public API. So ILMerging and internalizing wasn't an option either. (ILMerging and non-internalizing will result in a namespace clash).

So instead, I decided to rename the dependency in one of the projects, including the namespace of all the types using Mono.Cecil and a powershell script:

# Powershell needs to be configured to be able to load .net4 assemblies http://devonenote.com/2011/01/configure-powershell-to-use-dotnet-4-0/
function Get-ScriptDirectory
{
	$Invocation = (Get-Variable MyInvocation -Scope 1).Value
	Split-Path $Invocation.MyCommand.Path
}

$loc = Get-ScriptDirectory
[Reflection.Assembly]::LoadFrom("Mono.Cecil.dll")
$dir = "$loc\packages\Package.1.0.0\lib"
$assembly_dll = "$dir\TheAssembly.dll"
$assemblyDefinition = [Mono.Cecil.AssemblyDefinition]::ReadAssembly($assembly_dll);
$assemblyDefinition.Name.Name = "NewName"
$assemblyDefinition.MainModule.Name = $assemblyDefinition.MainModule.Name.Replace("TheAssembly", "NewName")
# Change the namespace root of all the main module types
foreach($typeDefinition in $assemblyDefinition.MainModule.Types){
	$typeDefinition.Namespace = $typeDefinition.Namespace.Replace("RootNamespace", "NewRootNamespace");
}
$assemblyDefinition.Write("$dir\NewName.dll");

 

One side affect of this is that it will break debug symbols.

This is something I would do as a last resort, but useful to know nonetheless.