Assembly Display Name


Every assembly has so-called “Display name”. As of today, the display name of an assembly is shown as “name, Version=xx.xx.xx.xx, Culture=xx, PublicKeyToken=xx”. It starts with a “name”, then a bunch of “key=value” pairs, separated by comma. Thos keys are called “attributes”. The “name” part needs a little explanation, while the other parts are obvious.

The “name” part is usually the file name of the assembly, excluding the extension. So for assembly foo.dll, the “name” part is “foo”. Of course, since I said “usually”, there are times when the “name” part is not the same as the file name excluding extension. I will discuss this in a bit.

Before we talk about that, first let’s talk about what characters are allowed in the “name” part. We know the assembly will exist in file system in as a file. So the “name” must be acceptable by file system. This means path separators (‘\’ and ‘/’) are illegal in the “name” part. The “name” may also need to be presented in an XML config file. So the characters in the “name” must be within the range defined by XML specification. Specifically,

http://www.w3.org/TR/REC-xml/

2.2 Characters

Character Range
[2]    Char    ::=    #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] /* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */

Now back to when the “name” part is different from the file name excluding extension. The display name must be able to round trip. Say you have an AssemblyName class, you can get its display name by calling either AssemblyName.FullName, or AssemblyName.ToString(). Now once you have the display name, you should be able to parse the display name, and get back the original AssemblyName class. If you can’t do that, it will be utterly confusing.

This requirement means we may have to escape a few characters. At minimum, we have to escape the comma character(‘,’) when it is in the file name, since we are using the comma as the delimiter in assembly display name.

Here is an example:

C:\>more “test,comma.cs”
using System;
using System.Reflection;

class test
{
    public static void Main()
    {
        Console.WriteLine(Assembly.GetExecutingAssembly().FullName);
        Console.WriteLine(new AssemblyName(Assembly.GetExecutingAssembly().GetNa
me().FullName).FullName);
    }
}

C:\>”test,comma.exe”
test\,comma, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
test\,comma, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null

You can see that we escaped the comma with character ‘\’. The example also shows we round tripped the display name.

The example is compiled and running under v2.0 beta1. In v1.0/v1.1, we did not handle comma in “name” correctly.

We did not provide a way to translate assembly display name to AssemblyName class in v1.0/v1.1. This is added in v2.0 (public AssemblyName(String assemblyName)).

You should never attempt to parse the display name manually. Use AssemblyName’s constructor, and copy the interesting properties.

In v1.0/v1.1, if the display name contains attributes we don’t understand, we will happily ignore those attributes. This has been causing problems for us. In v2.0, we change the behavior so that when we see unknown attributes, we will fail the parsing. If this causes problem for you, you can set registry [HKLM\Software\Microsoft\Fusion!UseLegacyIdentityFormat] to 1 to go back to the old behavior.

http://lab.msdn.microsoft.com/productfeedback/viewfeedback.aspx?feedbackid=bab82d4a-62c8-484a-a0aa-149646076b18 is an example when the new behavior breaks applications. But this is a rare example where the MSI package is mis-authored in the first place.

Comments (14)

  1. David Levine says:

    This is very interesting – your blogging has become required reading.

    I’d like to recommend one small change or addition – rather then require us to edit the registry to change the behavior of the parsing please provide a property that we can set programmtically. I prefer a situation where the environment is known and the executable does not have to go spelunking around the registry to determine how the system will react, especially since access to the registry may be restricted.

    Thanks.

  2. Kevin Westhead says:

    You mentioned in a previous post that loading based on ProcessorArchitecture is automatic, so I take it that ProcessorArchitecture is not part of the display name and there is no support for it in the AssemblyName class at v2.0? Does that mean there is no way to explicity load an assembly based on architecture? For example, if I have 32-bit and portable versions of an assembly in the GAC, can I explicitly load the portable one? Do you also know if it will be possible to redirect assembly binds based on architecture?

  3. David,

    We also have an environment variable for you. Set UseLegacyIdentityFormat=1, and you are set. I did not mention this in the main blog, because for the most people, it is the same as the registry key. To affect services like MSI, the environment variable has to be global. And MSI packages will suffer the most from this change.

    Kevin,

    I’ll talk about those in a separate blog. For short, you probably want to change the version number so that the 32 bit one and the portable one (MSIL) will not have the same version number. And Yes, it is possible to redirect assembly binds based on architecture.

  4. Thomas Olsson says:

    I was the one that sent the "bug" report you are mentioning: http://lab.msdn.microsoft.com/productfeedback/viewfeedback.aspx?feedbackid=bab82d4a-62c8-484a-a0aa-149646076b18

    Just for your information it might be interesting to know that the installation package was created with Wise for Windows Installer 5.2 and the attributes were added automatically by the Wise program.

    Even if it is mis-authored, it might not be that rare. Wise for Windows Installer is quite popular.

    I have tried to find information about what to include the MsiAssembly table in the installation programs, but have not found any good reference.

  5. Thomas Olsson says:

    You say "This has been causing problems for us". What kind of problems?

    What are the drawbacks of setting UseLegacyIdentityFormat?

  6. Thomas,

    Thanks for the bug report. Much appreciated.

    WISE installer has caused other problems for us. It really let us think many times about backward compatibility, and doing things the right way.

    The specific problem with the old parser is that, it tries to understand new identities(identities with new attributes not in the old .Net framework version). But it ignores the attributes it can’t understand. Informations are losted in transition. When you make decision based on the lost information, many bad things can happen.

  7. And to answer what should be included in MsiAssemblyTable, it should be things defined by Fusion.

    In v1.0, it is name, version, culture, publickeytoken. In v1.1, we added fileversion. In v2.0, we added processorarchitecture.

  8. Thomas Olsson says:

    What kind of problems can I get by setting UseLegacyIdentityFormat?

  9. It is only a problem if Whidbey CLR tries to intepret an Orcas (the version after whidbey) assembly identity. You probably won’t see any problems for several years, until Orcas comes along. And you will probably still be fine if your whidbey application don’t try to understand Orcas assemblies.

    Of course, the old parsing code does not handle special characters like "comma" correctly, and it does not validate the assembly name is of correct unicode characters. But I don’t know how much this concerns you.

  10. In my previous blog Assembly Display Name, I talked about some change we made in .Net framework 2.0 around…