3

After building my class library, I have several .dlls in my bin/Debug directory (some are from my own project while others are from third-party libraries). For example,

MyLibrary.dll
Newtonsoft.Json.dll
NLog.dll

I would like to rename these assemblies so that they include their version number. For example,

MyLibrary-1.0.0.0.dll
Newtonsoft.Json-10.0.3.0.dll
NLog-2.0.0.0.dll

What's the best way to do this? I can't just rename the files. I need to change the assembly names themselves, and propagate those changes to whatever depends on them.

So far, I've found the following solution (see https://stackoverflow.com/a/21753873/1383366):

ildasm /all /out=MyLibrary.il MyLibrary.dll
ilasm /dll /out=MyLibrary-1.0.0.0.dll MyLibrary.il

I'm not just not sure whether this is enough to properly change the assembly name, and I don't know the best way to propagate the name change.

redcurry
  • 2,381
  • 2
  • 24
  • 38
  • Why do you need to do so and which .NET version are you using so far? – Pavel Anikhouski Jun 04 '20 at 20:47
  • On Linux they name the file with version extensions and sym link the simple name to the versioned name. This way, you can revert easily. – David G. Pickett Jun 04 '20 at 20:51
  • @PavelAnikhouski We're using .NET 4.0 for most projects, while some projects are on .NET 4.5. The reason we want to do this: Our library is a plugin for a third-party application (outside our control) that loads our library into the primary AppDomain. We don't want to cause any conflicts with other plugins that may reference some of the same libraries. – redcurry Jun 04 '20 at 20:53
  • So you picked the worst possible solution to a problem we know nothing about. Look at the ILMerge utility, perhaps. – Hans Passant Jun 04 '20 at 21:38
  • @HansPassant I didn't pick a solution. I asked for help and I tried to be helpful by showing a solution I found. If my question is not clear, you can help me by asking what to clarify. I'll look into ILMerge. Thanks. – redcurry Jun 04 '20 at 21:47

1 Answers1

2

I don't think it's a good idea to rename references after your project is compiled with them and not sure why you think this is needed to do. It might indicate that this is a solution to some other problem (XY problem?). Maybe a better packet manager would help - Paket?

Anyway, you can rename references using Mono.Cecil.

A quick & dirty example how you could do it is the following:

string fileName = args[0];
string path = Path.GetDirectoryName(fileName);
var program = AssemblyDefinition.ReadAssembly(fileName);

foreach (var reference in program.Modules[0].AssemblyReferences)
{
    var referenceFile = Path.Combine(path, reference.Name+".dll");
    if (!File.Exists(referenceFile)) continue;

    var assemblyReference = AssemblyDefinition.ReadAssembly(referenceFile);

    var newReferenceName = $"{Path.GetFileNameWithoutExtension(referenceFile)}-{assemblyReference.Name.Version}";
    var newReferenceFile = Path.Combine(path, $"{newReferenceName}{Path.GetExtension(referenceFile)}");

    var assembly = assemblyReference.MainModule.Assembly;
    assembly.MainModule.Name = Path.GetFileName(newReferenceFile);
    assemblyReference.Write(newReferenceFile);       
}

program.Write(Path.Combine(path, "rewritten.exe"));

What we are doing is just renaming the filenames - adding a version and changing the name where each assembly is pointing to the disk. Keeping all the renaming with the same folder as you main assembly to include only local references.

Tested on a small example with a project reference and NuGet (NLog, Newtonsoft.Json as in your example) and it worked after the rewrite but keep in mind that it's just dealing with direct references and going into the references of references, if such exists, you would need to extend this example to your needs.

Paweł Łukasik
  • 3,893
  • 1
  • 24
  • 36
  • Thank you. I actually found Mono.Cecil after posting my question, and I implemented something very similar to your code (except it's recursive to handle references of references). The reason I believe I *need* to do this (and I see no other way) is that my assembly will be loaded as a plugin into the AppDomain of a larger application. I don't want there to be conflicts with other plugins loaded into the same AppDomain. For example, my plugin and someone else's plugin may use different versions of NLog. Do you see another way of handling this? – redcurry Jun 05 '20 at 14:07
  • Separate subfolders and AssemblyResolve event? Maybe renaming is the best option but there are some possibilities in the framework to resolve this issue and I would try them before resolving to external, custom-built solution as that would be more error-prone. – Paweł Łukasik Jun 06 '20 at 06:55