Latest Replies
Friday
Jan302009

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.

« Status of Lokad Shared Libraries and Roadmap | Main | DDD and Rule driven UI Validation in .NET »

References (2)

References allow you to track sources for this article, as well as articles that were written in response to this article.

Reader Comments (3)

Forgive my ignorance, but is this Cecil that you are rewriting the assembly with? In any case, that's a very slick solution you have there.

January 30, 2009 | Unregistered CommenterJeremy Gray

Exactly.
Lokad.Quality is just a set of helper extensions and classes on top of Mono.Cecil.

January 31, 2009 | Registered CommenterRinat Abdullin

I figured that was the case, but hadn't had a chance to dig into it myself to be sure. Thanks again for the quick turn-around on the namespace-adjusted version of the library. I have switched us over to that from our custom build and the ActionPolicy pieces that we were in need of are working wonderfully. Thanks yet again for the library itself. Lots of great stuff in there waiting to be found! :)

February 5, 2009 | Unregistered CommenterJeremy Gray
Comments for this entry have been disabled. Additional comments may not be added to this entry at this time.