Software Design Blog

Journey of Rinat Abdullin

How to Change Namespace of .NET Assembly?

As you know, one of the peculiarities of Lokad.Shared.dll (of Shared Libraries) is that it integrates into the System namespace, transparently providing some helpers and extensions that .NET framework does not have, yet.

However, this might feel uncomfortable if you want to use libraries just a for the retry policies, business rules or any other minor piece (thanks to Jeremy Gray for pointing this out).

So in order to deal with this we need some process that would create a copy of assemblies where all classes are moved from System.* to Lokad.*.

Well, it does not have to be more complex than that:

var codebase = new Codebase("Lokad.Shared.dll");
foreach (var type in codebase.Types)
{
  type.Namespace = type.Namespace.Replace("System", "Lokad");
}
codebase.SaveTo(output);

That’s all you need to move all type definitions in the library from the System* namespace to Lokad* namespace.

Since Lokad.Shared.dll has got a strong name, we just need to perform one more step and resign the assembly (SharedKey.snk is available in the trunk):

sn.exe -Ra Lokad.Shared.dll SharedKey.snk

If we want to migrate multiple assemblies at once, we’ve got to update their type references as well. Here’s how this could be achieved:

var codebase = new Codebase(assemblies);

var changes = new Dictionary<string, string>();

foreach (var type in codebase.Types)
{
  var oldName = type.FullName;
  type.Namespace = type.Namespace.Replace("System", "Lokad");

  if (type.IsPublic)
  {
    changes.Add(oldName, type.FullName);
  }
}

foreach (var type in codebase.GetAllTypeReferences())
{
  if (changes.ContainsKey(type.FullName))
  {
    type.Namespace = type.Namespace.Replace("System", "Lokad");
  }
}
codebase.SaveTo(output);

Now, wouldn’t it be nice to have XML file updated as well, so that IntelliSense could display helpful hints? It is really simple to achieve this:

var docs = assemblies
  .Convert(a => Path.ChangeExtension(a, "xml"));

foreach (var fileName in docs)
{
  var text = File.ReadAllText(fileName);
  var builder = new StringBuilder(text);

  foreach (var pair in changes)
  {
    builder.Replace(pair.Key, pair.Value);
  }

  var newPath = Path.Combine(output, Path.GetFileName(fileName));

  using (var writer = File.CreateText(newPath))
  {
    writer.Write(builder.ToString());
  }
}

This simple process has just been integrated into the build script of Lokad Shared Libraries. If somebody prefers to keep their System namespace clean of helper classes and contextual extension methods - just grab the download with “Lokad namespace” mark in it.

PS: Snippets above leverage latest version of Lokad.Quality.dll from the same project.