I'm referencing a signed assembly. In runtime it is ok for me to work with any version of that assembly, not just the one I compiled to.
How to achieve this?
No, that's not going to work. The CLR will verify the assembly version number, expecting to get the one that your main program was compiled against. You would have to use the <bindingRedirect> element in the app.config file to convince it that a different version is okay.
That's a slippery slope. Consider only changing the [AssemblyVersion] attribute if the public interface of the assembly changed and requires clients to be recompiled. Now the exception you'll get is one that identifies a real problem. This is another kind of slippery slope, but one you'll have much more control over.
For comparison, this is the way all the base assemblies in the .NET framework work. There have been many revisions of them between .NET 2.0 RTM and 3.5 SP1, including many invisible hotfixes. But the [AssemblyVersion] is still 2.0.0.0, Microsoft only modifies the [AssemblyFileVersion].
In the IDE, make sure "Specific Version" is set to false against the reference, or add <SpecificVersion>False</SpecificVersion> to the reference in the csproj.
Related
AssemblyA.dll refers to AssemblyB.dll
AssemblyB was rebuilt with new code, but not AssemblyA. Therefore, we no longer know for sure if AssemblyA is compatible or not. Maybe it will crash at runtime because some method or property was removed.
Theoretically speaking, is it possible to validate whether AssemblyA is compatible or not with AssemblyB, without having to actually rebuild it ?
The scenario you describe is called the DLL Hell. Wich is just the Windows Specific Subset of Dependency Hell. And prior to .NET (and outside of it) it is dang common. It comes from basically only identifying a DLL by it's name and path.
The .NET Developers knew of it and tried their damndest to avoid it. .NET will not just identify a referenced DLL by the name. It will use at least the Name, Version and Zertificate.
Two dll can have the same name. As long as their version is differnt, .NET will have no issue keeping them appart. .NET does not even has issues keeping them both in memory at the same time. You do not just build against the "System.DLL". You build agianst the "System.DLL. Version Y, Zerficate X".
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:
.NET runtime sees it at it sees System.dll (no need to deploy locally or provide a reference path)
MSBuild sees it when I do <Reference Include="MYASM" /> without needing a hintpath
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
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.
There are a few ways...
1) is to create a new setup and package this for the framework you target. You can Package this and have it deployed using the domain controller. When your users log in the domain will update the packages, this way you'll be able to deploy your software to specific users and or user groups. Depending on your infrastructure you'll have a software management infrastructure that you can use (2 links included).
2) Create a NuGet package if you're targeting developers. If your organisation host your own NuGet server limiting the distribution. Add the Package source to Visual studio open the Options Page, type NuGet in the search field and set the URL/ UNC path.
3) use OneClick deployment, this allows you to have the application download the updated dll's and install them on the machine. It requires a Code Sign certificate but you're probably signing your code anyway (better for Anti-Virus tools if you do).
Now linking your MyAsam.dll will be done by the application linking definition or IoC container. Basically, if it finds the dll and no version is defined it will take the first one it finds I think the order is 1 AppFolder, 2 GAC, 3 Path, not sure. This "take what you find" is generally referred to as "DLL-Hell", The NuGet and OneClick solution works best in this as You will always get the Updated dll that works for the application. Placing the DLL in GAC is going to get problematic if you have moe than 1 application using your dll and both need the "right" version where the "right version" differes between them....
If you have the source code available for MYASM.dll, then I would prefer adding a project reference to your consuming application. When doing so, Visual Studio shall create a GUID for all the referenced project.
Since version 3.0, .NET installs a bunch of different 'reference assemblies' under C:\Program Files\Reference Assemblies\Microsoft...., to support different profiles (say .NET 3.5 client profile, Silverlight profile). Each of these is a proper .NET assembly that contains only metadata - no IL code - and each assembly is marked with the ReferenceAssemblyAttribute. The metadata is restricted to those types and member available under the applicable profile - that's how intellisense shows a restricted set of types and members. The reference assemblies are not used at runtime.
I learnt a bit about it from this blog post.
I'd like to create and use such a reference assembly for my library.
How do I create a metadata-only assembly - is there some compiler flag or ildasm post-processor?
Are there attributes that control which types are exported to different 'profiles'?
How does the reference assembly resolution at runtime - if I had the reference assembly present in my application directory instead of the 'real' assembly, and not in the GAC at all, would probing continue and my AssemblyResolve event fire so that I can supply the actual assembly at runtime?
Any ideas or pointers to where I could learn more about this would be greatly appreciated.
Update: Looking around a bit, I see the .NET 3.0 'reference assemblies' do seem to have some code, and the Reference Assembly attribute was only added in .NET 4.0. So the behaviour might have changed a bit with the new runtime.
Why? For my Excel-DNA ( http://exceldna.codeplex.com ) add-in library, I create single-file .xll add-in by packing the referenced assemblies into the .xll file as resources. The packed assemblies include the user's add-in code, as well as the Excel-DNA managed library (which might be referenced by the user's assembly).
It sounds rather complicated, but works wonderfully well most of the time - the add-in is a single small file, so no installation of distribution issues. I run into (not unexpected) problems because of different versions - if there is an old version of the Excel-DNA managed library as a file, the runtime will load that instead of the packed one (I never get a chance to interfere with the loading).
I hope to make a reference assembly for my Excel-DNA managed part that users can point to when compiling their add-ins. But if they mistakenly have a version of this assembly at runtime, the runtime should fail to load it, and give me a chance to load the real assembly from resources.
To create a reference assembly, you would add this line to your AssemblyInfo.cs file:
[assembly: ReferenceAssembly]
To load others, you can reference them as usual from your VisualStudio project references, or dynamically at runtime using:
Assembly.ReflectionOnlyLoad()
or
Assembly.ReflectionOnlyLoadFrom()
If you have added a reference to a metadata/reference assembly using VisualStudio, then intellisense and building your project will work just fine, however if you try to execute your application against one, you will get an error:
System.BadImageFormatException: Cannot load a reference assembly for execution.
So the expectation is that at runtime you would substitute in a real assembly that has the same metadata signature.
If you have loaded an assembly dynamically with Assembly.ReflectionOnlyLoad() then you can only do all the reflection operations against it (read the types, methods, properties, attributes, etc, but can not dynamically invoke any of them).
I am curious as to what your use case is for creating a metadata-only assembly. I've never had to do that before, and would love to know if you have found some interesting use for them...
If you are still interested in this possibility, I've made a fork of the il-repack project based on Mono.Cecil which accepts a "/meta" command line argument to generate a metadata only assembly for the public and protected types.
https://github.com/KarimLUCCIN/il-repack/tree/xna
(I tried it on the full XNA Framework and its working afaik ...)
Yes, this is new for .NET 4.0. I'm fairly sure this was done to avoid the nasty versioning problems in the .NET 2.0 service packs. Best example is the WaitHandle.WaitOne(int) overload, added and documented in SP2. A popular overload because it avoids having to guess at the proper value for *exitContext" in the WaitOne(int, bool) overload. Problem is, the program bombs when it is run on a version of 2.0 that's older than SP2. Not a happy diagnostic either. Isolating the reference assemblies ensures that this can't happen again.
I think those reference assemblies were created by starting from a copy of the compiled assemblies (like it was done in previous versions) and running them through a tool that strips the IL from the assembly. That tool is however not available to us, nothing in the bin/netfx 4.0 tools Windows 7.1 SDK subdirectory that could do this. Not exactly a tool that gets used often so it is probably not production quality :)
You might have luck with the Cecil Library (from Mono); I think the implementation allows ILMerge functionality, it might just as well write metadata only assemblies.
I have scanned the code base (documentation is sparse), but haven't found any obvious clues yet...
YYMV
I've been asked to add automatic numbering to assemblies in our code library. I've been changing versions from the default 1.0.0.0 to 1.0.* like this:
[assembly: AssemblyVersion("1.0.*")]
It generates a number as I'd like.
However, the code library has many hundreds of DLLs, with many referencing each other. Now when I compile some projects they complain that the version of a DLL needed by a referenced component is not correct and they won't build :(
How can I make this work? We need it so that when a DLL at the bottom of our code library hierarchy is compiled, all other DLLs that reference it work correctly without needing recompiling.
The error I get is like this:
Error 1 CA0058 : The referenced assembly 'Library1, Version=1.0.4146.17993
, Culture=neutral, PublicKeyToken=d9c65edd2096ad48' could not be found. This assembly
is required for analysis and was referenced by:
D:\Work\Source Code\Library\Library2\bin\Release\Library2.dll.
The version 1.0.4146.17993 is not correct - the DLL has a higher value. The DLLs are set to Copy Local because the software we deliver requires it (don't ask why). The DLL that's copied locally is the one with the higher version number, which is the one we want it to be.
So far I've tried changing the references to set the "Specific Version" flag to false but this didn't help.
The version numbers that VS generates when you use the 1.0.* syntax are not necessarily going to increment in sequence. The documentation has this to say (emphasis added):
You can specify all the values or you can accept the default build number, revision number, or both by using an asterisk (). For example, [assembly:AssemblyVersion("2.3.25.1")] indicates 2 as the major version, 3 as the minor version, 25 as the build number, and 1 as the revision number. A version number such as [assembly:AssemblyVersion("1.2.")] specifies 1 as the major version, 2 as the minor version, and accepts the default build and revision numbers. A version number such as [assembly:AssemblyVersion("1.2.15.*")] specifies 1 as the major version, 2 as the minor version, 15 as the build number, and accepts the default revision number. The default build number increments daily. The default revision number is random.
If it's vital that you get versioning exactly right, I highly recommend that you use a third-party solution. The Build Version Increment add-in is excellent.
What you want to do is manage the assembly version yourself. Only increment this when you make a breaking change to the assembly's public interface. Changing this attribute makes your assembly incompatible with other assemblies that reference it, even if you didn't change a thing in your code. Instead, the only thing you want to automatically increment is the assembly file version. Unlike the assembly version, this attribute is not checked by the CLR to determine compatibility.
The Build Version Increment add-in gives you the kind of fine-grained control over what is incremented that you need to get this right. It's what probably should be included in VS to begin with.
This is actually a pretty indepth question, and I hope someone answers this in detail for you, but my 2 cents after you get the assembly infos under control is you should look at using Nuget to manage your dependencies. This way when team A releases v2 of assembly X, all they do is put it on your Nuget repo (network share probably) and then you can basically right click < update inside your projects that consume the DLLs.
I would also recommend looking at http://semver.org/ and use Semantic Versioning, if you don't want to follow a system like this one (or institute a similar standard for your shop), it's probably not worth even trying to version your DLLs you're just going to give yourself massive headaches. However using Semantic Versioning will make your version numbers actually MEAN something. And not just be whatever felt like being tagged onto the current version.
Note that the Revision number is not random. It is the time of day of the build. The Build is the day number.
See VisualStudio: translating a build version to a calendar date
delete your reference (in the project that uses it) and re-do it by pointing to the project reference type.
PS: If when you are adding the reference, you choose browse and point to a place the dll will always be, the reference will not be broken!
> However, the code library has many hundreds of DLLs,
If it is ok for you that all source projects and their generated dll-s have the same version-number you can put the versionnumber into one file that is shared between all dlls as described in
shared AssemblyInfo.cs. So you (or the version-number-generator you are using) have to update only one file if there is a new relase/Version.
This does not answer your original question but may be a simple workaroud for the dependency problem.
I would like to keep version in my .net applications and let the .net to manage it. I don't really understand how it works. Is the version number per project ? How .net manages versions? If anyone could please explain it briefly i will be grateful.
What I usually do is to keep a SolutionInfo.cs that contains all the attributes that are common for the projects of my solution, for example the version-number. I keep this file in the solution root.
I then link that file into the project (right click the project and Add->Exsiting item... -> Add as link (the little arrow on the add button)).
I then can increment the version number in a single place and it will be updated in all the projects that links that file.
For more information on that for example see: http://jebsoft.blogspot.com/2006/04/consistent-version-numbers-across-all.html
The version number is per-project (.csproj file), so per built .dll or .exe file. The version number is embedded in the .dll or .exe, and can be viewed using (for example) Windows Explorer by right-clicking on the file and selecting Properties.
MSDN contains an explanatory article about how to use AssemblyVersion and AssemblyFileVersion at http://support.microsoft.com/kb/556041
[AssemblyVersion] is a very big deal in .NET. Every type in your program is imprinted with the assembly version, it is part of the type identity. In other words, when the version of your type changes then you should also change the assembly version. This forces all other assemblies that use your type to be recompiled.
One thing you can do is to let the build system automatically increment the version. You can't call this 'managing the version' by any stretch of imagination. Because now just rebuilding your assembly, even without making any change in the source code, will make your assembly incompatible with other code that uses the types in that assembly.
Clearly this can only work well if you recompile all the code in your solution.
Well, that's not great unless you like sword fighting. Furthermore, sometimes you want to make a simple bug-fix in your code. The result is an assembly that's still 100% compatible with the original version. And you don't need nor want to recompile everything else that uses it. You just want to send that one assembly to your customer. Clearly that can only work well if you don't let the version increment automatically.
So what you really need is some kind of tool that can magically determine that your source code, the publicly visible part of it, is no longer compatible with a previous version. Or the changes you made to the non-visible part of it are changing the behavior of the code too much to disallow other code that use your types to continue to use it without some changes in their code.
There's only one tool that I know of that can do this, the one we have between our ears.