Search code examples
c#.netvisual-studioassembliesgac

Deploy assembly as part of .Net Framework


I have an assembly (MYASM.dll) targeting .NETFramework 4.0 (with a strong name)

I want to deploy this assembly in a way it is part of .NETFramework (or the whole system thinks it is) on target machine.

By that I mean:

  1. .NET runtime sees it at it sees System.dll (no need to deploy locally or provide a reference path)
  2. MSBuild sees it when I do <Reference Include="MYASM" /> without needing a hintpath
  3. User is able to make Add reference in Visual Studio and that introduces <Reference Include="MYASM" /> without the strong/full name

I have solved 1. (and apparently 2.) by adding it to the GAC. But this is apparently not sufficient.

I have partially solved 3. by putting my assembly in a special folder ([INSTALLFOLDER]\lib) and set registryKey HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v4.0\AssemblyFoldersEx\MyAssemblies

Then I can do Add reference, but then I get:
<Reference Include="MYASM, Version=1.1, Culture=neutral, ..." /> in my csproj instead of just <Reference Include="MYASM" /> as I'd like.

With the second approach, if I manually edit the csproj, everything is OK, but I can't ask my users to do that.

What should I do here?

[EDIT] apparently it’s not obvious I have my own MSI. But yes I have. I don’t control users machines with a magic wand


Solution

  • No, you've taken this as far as it can go. It isn't actually that obvious how VS figures out to put the partial assembly name into the project file. This is not public code and can't be tampered with. Pretty sure it does not use a white-list and it can't pay attention to the reference assembly location.

    Most likely detail is the PublicKeyToken of the assembly. The framework assemblies always have to exact same value for them, b77a5c561934e089. Its value is even prescribed in the CLI spec (Ecma-335). Next most likely by a considerable distance is the signing certificate, identifying the assembly as owned by Microsoft. Both however present the exact same problem, you can't get the private key that is required to strong-name or sign the assembly. They are locked inside a vault in Redmond, only trusted build engineers have access to them.

    There is another nasty little detail you are overlooking, you are not nearly scared enough of DLL Hell. Cold hard fact is that if you ever expose the assembly in the GAC on another machine that is not in your control then you can never change it again. You can no longer modify the public interface of the assembly. Can't add a new public method or type, can't modify the arguments and return type of a method, can't add an enum member, etc. Even harsher, something Microsoft worries about, is that you can't really change private and internal members either. Programmers have a knack for using Reflection to poke around, terrific bug fixing tool. But at least you can tell them "don't do that!".

    Making such modification requires increasing the [AssemblyVersion]. Now you get a different kind of DLL Hell, the machine might not have been updated by your installer. Or worse, a solution uses projects that have different references. Microsoft had to solve this problem for framework assemblies, they did so by modifying the CLR. Automatically forwarding old versions to new ones. The basic reason why using an assembly built for .NET 2.0 can be used in a .NET 4.x project. You can't get that kind of service for your own DLL.

    "Don't do it" is the only good advice, getting in DLL Hell trouble is however a terrific learning experience I can recommend for anybody. Hell has to be experienced to be feared.

    Best advice is to publish a Nuget package. They do the exact opposite, never deployed in the GAC and version numbers change very rapidly. But always available when a programmer needs it.