Using different versions of the same assembly - c#

I have a project where I simultaneously must use reports built in ActiveReports 2 and ActiveReports 6. Overall, it works ok, but some of the helper assemblies use the same name. For instance, to be able to export to PDF, both versions use an assembly called ActiveReports.PdfExport.dll. The corresponding assemblies are different, of course.
Note that I don't access the ActiveReports.PdfExport.dll directly - this is handled by the ActiveReports runtime.
I can't find a way to include both of them into the project. Is there a way? Is GAC the answer?

Creating separate external aliases for each assembly will help if you have type name collisions. For assembly name collisions, take a look at ILMerge; you can combine all related assemblies together. You'd create an assembly for ActiveReports 2 that combines all its required assemblies and another for ActiveReports 6.

GAC is one way, but Fusion resolution has a lot of flexibility in it that might suffice. Fusion will probe in the BaseDirectory for the assembly name .[DLL|EXE]. If not found it will probe BaseDirectory\Name.[DLL|EXE]\Name.[DLL|EXE]. So you might be able to get away with creating a folder named ActiveReports.PdfExport.DLL in your Bin folder and dumping the older version of the file in there.

Yes, you have to put both into GAC (this is what it's made for, in case of client assemblies).
My idea: create two libraries-helpers, reference each to appropriate assembly, register them into some kind of factory or manager and call specific one when you need.

Related

Create placeholder .NET assembly [duplicate]

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

Load an assembly from another location not in the GAC

I have several applications which are required to use the same assembly. This assembly may be changed regularly, and can be installed by different MSIs. For this reason, I do not want to put it in the GAC, it can become a deployment nightmare over time.
If I turn the CopyLocal attribute for this assembly to NO in the application, how do I tell the runtime where to look for the assembly?
E.g. the application is loaded in C:/Program Files/<some directory>/bin
The DLL is in C:/<some other directory>
Is it thus possible to load the assembly in this way?
I've had a look at <codebase>, but I'm not sure the assembly can be strongly signed. And probing seems to work only for the private paths specified as subdirectories of the application?
Please let me know. Thank you.
Use Assembly.LoadFrom to load the assembly into memory, then you can use Activator.CreateInstance to create an instance of your preferred type. You need to user reflection for this:
Assembly assembly = Assembly.LoadFrom("c:\\path\\MyDll.dll");
Type type = assembly.GetType("MyClass");
object instanceOfMyType = Activator.CreateInstance(type);
Take a look on reflection in order to create instances with parameters.
Why do you want to set CopyLocal to "No"? The usual way to avoid "DLL hell" (aka "deployment nightmare") is to ensure that DLL dependencies are copied into the same directory with your program. IMHO, this is the simplest, most straightforward way to guarantee you are loading the DLL you want.
Note also that if you sign the DLL, install it in the GAC, and then in your own program require a specific version (or a minimum version, depending on your needs), that should also address the "DLL hell" scenarios. I.e. the presence of other versions of the DLL won't conflict, because you've required a specific version and .NET can reliably distinguish the correct version from an incorrect one.
Barring those approaches...
It's not clear what your exact requirements are. However, if you are trying to provide a way to identify an assembly that's not in the usual assembly-loading paths, there are at least a couple of mechanisms you can use.
One way is to use ApplicationBase and PrivateBinPath to control how .NET searches for your assemblies.
Another way is to handle the System.AppDomain.AssemblyResolve event.
That event will be raised any time .NET tries to load a referenced assembly and can't find it. Your handler can then perform whatever search it needs to (or just use a fixed path for that matter), load the assembly itself (e.g. using Assembly.LoadFrom()), and then return that via the event's arguments object.
Note that the AssemblyResolve event is only raised if .NET can't find a DLL to load. So that would not be an appropriate solution if it's not tolerable to have a different instance of the DLL that satisfies the reference requirements for the program of that DLL.

DLL Hell issues: Assigning strong names

I have two DLLs, app1.dll and app2.dll, that use the same third dll, util.dll, which might have slightly different behavior when built for a specific app.
I want to achieve that app1.dll and app2.dll are isolated concerning the versions of util.dll that they use. On MSDN, I read that assigning a strong name to util.dll is the solution, i.e. that this strong name contains the name and version of the dll as well as the fingerprint due to signing.
I currently build util.dll...
for app1 with KeyFileApp1.snk and version 1.0.0.1
for app2 with KeyFileApp2.snk and version 1.0.0.2
and this seams to work on the target machine when deploying the apps with the respective util.dll build.
However, I have some ambiguities:
Would it be enough to build util.dll always with version 1.0.0.0 but different key files for both apps and having both apps using the right dll in the end?
Are the strong names only considered when putting a dll in the global assembly cache or also when having it as private assembly?
yes you can have both with the same name and version, but different public key. Is it good/maintainable solution - up to you. Will likely confuse more people than you want. I.e. no regular person will be able to tell you "public key" used by DLL, but most people can right click and check details to see version (if you set it properly on your assemblies).
strong name is always considered. Note that if you have local and GAC copy GAC one will always be used if version in GAC is acceptable.
Notes:
strong names are "viral" as you can't have strongly named assembly depend on one without strong name. Be careful as you'd need many for your assemblies to be strongly signed (not a bad thing by itself) and have good versioning plan.
you may eventually endup with multiple versions of the same assembly loaded into process - either prepare for it or use publisher policy to map all versions to latest.

Referencing a 3rd party assembly which is not located in the root location

I have a Visual Studio 2010 C# project which creates an .exe and this project is using some 3rd party class library.
My project is located in: /MyFramWork/tests/test1
3rd party library is located at: /MyFrameWork/bin/utils/
I am adding the reference to the library by using References->Add Reference->Browse. I can see that in the project file all is fine:
....\bin\utils\log4net.dll
False
I would like to reference the 3rd party library without using the option "Copy Local". However if I don't use the option, the library is not found and I get an exception.
My question is: Is there a way to specify that the 3rd party library should be found at ....\bin\utils. It seems that when the .exe gets build the information from the .csproj gets lost.
By default, .NET apps look for their dependencies in only two places: the EXE directory, and the GAC (Global Assembly Cache).
You have three choices:
You can make sure the dependency gets copied into the same directory as your EXE (this is what Copy Local does). This is the best choice most of the time, which is why it's the default when you reference an assembly that's not already in the GAC.
You can install your dependency into the GAC using gacutil. This might be a good choice if your dependency isn't going to change, is going to be in a different location on every development machine (i.e. if relative paths won't work well), and if you want to use it from many different projects. But it's a major pain if the dependency is still under active development and changing frequently. You'll also need to make sure to put the DLL into the GAC on every computer you deploy your app to.
You can customize the dependency-loading behavior so it looks in other places, as Hans noted in his comment. This is an advanced option and comes with a whole new set of headaches.
Normally, you would just use Copy Local; it's a very sensible default. You should need a fairly compelling reason to do anything different.
Use the <probing> element to specify where the CLR should search for your assemblies. The only restriction is that the assemblies must be located in subdirectories of your application's base directory.
For example, if your application base directory is C:\MyFramework, then you could have your assemblies in C:\MyFramework\bin.
Have a look at this article to learn how the CLR searches for assemblies.
If you need to load assemblies from custom locations, you could try the Assembly.LoadFile Method.
The following links may be useful:
C# - Correct Way to Load Assembly, Find Class and Call Run() Method
http://www.csharp-examples.net/reflection-examples/
It's me Potzon. I am still investigating this incredibly silly problem.
I have been hoping for some elegant solution. I am about to build fairly large framework with lots of assemblies which would be placed inside /Framework/bin/. However I wanted to have some directory structure inside the the directory, for example /bin/utils, /bin/test, /bin/devices/ and so on.
One possible solution that I have found is to define environmental variable DEVPATH (see here http://msdn.microsoft.com/en-us/library/cskzh7h6.aspx) but it turns out that .net4 is not using this variable when an assembly is run independently (outside the visual studio), or at least this is the case for me - I can't make it work.
It seems that the solution to put all the assemblies inside the /bin directory without using sub-directories is the best. I think I will give up and just do it this way.

When should we not create Assembly's strong name? What are the disadvantages of "strong named assembly"?

I have a project, i.e. library.exe. In this I have referenced an assembly (logging.dll ver 1.0.3.0) and I have given this assembly a strong name.
Now suppose I changed a method in logging.dll and made version 1.0.4.0.
Now when I copy/replaced the old DLL with this new one I got an exception.
I know that exception is because I have changed version number of the DLL. As it was a strong name DLL it's not allowed unless I rebuilt library.exe.
What I want to say with above story is
Use strong name with assembly only when we have to add it to GAC.
If we have an application where individual assemblies requires updating do not use strong named assemblies.
Am I correct with point 1 and 2?
When should strong named assemblies not be used?
What are the disadvantages of "strong named assembly"?
It is only really needed if you want to place your assemblies in the GAC, but it also helps against tampering. It is fairly easy to change the code in an assembly so this gives bad people an advantage. When you are using strong named assemblies you are signing it with a private key only you have. People could still change your assembly, but they can't give it the same strong name, because they do not have your private key. In that case .Net refuses the assemly tamperd with. When they sign your assembly with a new private key the .Net still refuses to load it since the identity of the assembly has changed.
There are several ways to solve the versioning problem. When your application wants to load a v1 assembly you could tell it to look voor a v2 anyway. See here for more information. The other option would be not to change the Assembly Version at all, but to change the File Version of the assembly only. For .Net the assemblies are the same, but you and your installer can still see which one is newer. See the AssemblyFileVersion attribute.
Both correct.
You don't need a StrongName if your signing the assembly afterwards, like with a real certificate.
In my oppinion strong naming is not realy worth anything, see this link for example. Well you need it for placing an assembly into the GAC but that's it.

Categories