Assembly resolving and merged assemblies - c#

Can anyone tell me in what order assembly resolving takes place when I have the following situation?
In my bin I have my exe and 2 dll's:
Assemblies A (version 1), B and C merged into X (so 4 assemblies into 1)
Assemblies A (version 2)
all references I made did not include the UserSpecificVersion parameter.
Now, during a call in my exe, which A is being used?
Also, during a call in assembly B, which A is being used?
And what if it is the other way around (so first from B and then my exe)
Is there any documentation on this?

all references I made did not include the UserSpecificVersion parameter.
I'll assume you actually meant the "Specific Version" setting for a reference assembly and that you set it to False. This has no effect at runtime, only at compile time. When you added the assembly, it recorded the [AssemblyVersion] of the reference assembly. If you then, later, recompile your program but it finds a reference assembly with a different version then it won't complain but use the new one as-is. This is in general risky and you'd only do this when you try to limp along after you lost the original reference assembly and have no clue to what degree the new one changed. Always leave this setting at the default of True, only use False if you dug yourself a deep hole you cannot get out of.
At runtime it will always insist on finding the assembly with the correct display name and [AssemblyVersion] that was recorded from the reference assembly. You'd in general have trouble when you have two assemblies with the same name and namespaces, you tend to need extern alias to dig yourself out of that hole. Using ILMerge could indeed be a workaround, that changes the display name of the assembly. That however still leaves you with conflicting namespace+type names, it isn't clear how you sailed around that obstacle.
So the typical outcome is that the EXE will try to find A2, using the renamed assembly display name, and B will try to find A1. I can't nail it down with 100% fidelity from the provided info. If you have a non-typical case then use Fuslogvw.exe to get a trace of the assembly bindings. Be sure to select the "Log all binds" option.

Related

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.

Strong names, and their relationship to referenced assemblies

Here's the problem I have. I need to inherit from two classes in C#, which can't be done. So I've set my class to inherit from one class and implement an interface for the other. I did the interface first, and all worked well. Then issues started arising when inheriting from the class. At first, it would compile, but on implementing the class I would get:
The assembly 'XXXXXXX\bin\x86\Debug\Resource.dll' does not have a strong name.
Easy enough, I signed my projects. But now I get an issue when building with my references that were working before:
The type 'WPResourceEvtLib.IWPResourceEvt' is defined in an assembly that is not
referenced. You must add a reference to assembly 'Interop.WPResourceEvtLib,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=567474567455'
I have WPResourceEvtLib.tlb which has been registered, and a Interop.WPResourceEvtLib.dll, whoch shouldn't be required. And if I add the Interop.WPResourceEvtLib.dll to the references I get:
Cannot embed interop type 'WPResourceEvtLib.tagWPResErrorType' found in both assembly
'XXXXXXX\Interop.WPResourceEvtLib.dll' and
'XXXXXXX\obj\x86\Debug\Interop.WPResourceEvtLib.dll'. Consider setting the 'Embed
Interop Types' property to false.
This is .net3.5, so there is no 'Embed Interop Types' option, but I did find those options in the cproj files - they did nothing though. I'm either so very close, or I'm completely wrong in my implementation. What could it be?
Sorry for a mostly non-answer, but the amount of supporting questions got large, and that way it will be more readable.
First, what is the nature/kind of XXXXXXX\bin\x86\Debug\Resource.dll? If .Net, then why TLB file? Is it COM and native? Or COM/OCX? Or just a normal .Net assembly with some ComVisible types? What is WPResourceEvtLib? Is it the "name" of that Resource.dll?
"Back then", when your assemblies were not signed, everything worked fine? What exactly have you changed? Which project got signed and what are the relations/references between the projects? Are all those projects inside the same solution and are they built simultaneously and they do reference-by-sibling-project, or maybe you build some parts separately and only reference-by-GAC, or, worse, reference-by-path-to-DLL? It might be just that you forgot to refresh/rebuild some references and they still link to the old unsigned versions?
Finally, why do you think that your implementation of inheritance and interface caused anything? Did you do some low-level stuff like manually writing IL, COM metadata, etc? The only thing the inheritance/implementation problem could actually cause is to force you to reference an assembly X to get the definition of the base class and assembly Y for the definition of interface, nothing more. It has nothing to do with signing or being unsigned. It all just about references to correct assemblies.
Let's start guessing. So, back to the references. First error message tells you that, your project references assembly X that was using another assembly Y and your project tries to use a class/type that belongs to Y but without explicitely referencing the Y (ie. it peeked it from X assembly). It cannot be done. When T.dll uses X.dll that uses Y.dll, whenever X.dll returns a Y-type to the client from T.dll, the T.dll must reference the Y.dll or else it will not be able to use that Y-object. Now note the change: when unsigned, everything worked. So your project "unsigned T" had used "unsigned X" which used "unsigned Y". If that compiled, it means that T reffed both X and Y. After signing you got error that "signed T" does not reference "signed Y". How did does SEE the new signed Y? If it REFERENCED it, then the error would not show up. Hence, it means that "signed T" has indeed referenced "signed X" which indeed is referencing "signed Y". BUT: as the error claims that signed T does not reference signed Y, it may mean that the signed T project is still referencing the old unsigned Y. Now if you actually add the reference to the signed Y, you will get a type clash: same types will be visible in old unsigned Y and new signed Y. Hey, everything seems to fit.
It might have happened if you added a reference from T to a Y.dll by path and forgot to rebuild that Y.dll at that path. That can be really silly: i.e. in T you have clicked "add reference" and "browse" and pointed to "Release\Y.dll", and then forgot to rebuild it and only have rebuild the T/X/Y in DEBUG modes. That way, one old unsigned version would linger in the cache directories and the T would still try to use it, while the referenced X would already be relinked to new signed Y.
have you tried the simpliest possible thing: clean everything, delete all bin/obj folders, remove all references, add the references back and rebuild?

Loading an assembly / module into a dynamic assembly

I have one assembly that's created already, say Static.dll, and a dynamic assembly I'm creating at runtime, say Dynamic. Dynamic creates some IL code to create a new type from Static.dll. When Dynamic is created (it saves successfully), the executable, when ran, errors out because it's unable to load the assembly Static.dll type. I believe this is happening since the Dynamic exe output can't find this dll (or at least this is my guess).
How can accomplish adding in this Static.dll reference so that when someone runs the resulting executable output of Dynamic that it can find the referenced types?
I know about Assembly.Load(), but this alone doesn't change anything. Or at least, I'm not sure what this gives me since I don't need to use the type at runtime, but rather when running the Dynamic executable.
Lastly, I control the Static.dll, so if there is something I can do with the project to fix it, It could be done, however, it does need to remain separate (I don't want to Emit this library for every time I create a dynamic assembly). Basically, I think I want to have my dynamic assembly to have a .assembly extern mscorlib in it's manifest save Static is place of the mscorlib.
Thanks
How can accomplish adding in this Static.dll reference so that when someone runs the resulting executable output of Dynamic that it can find the referenced types?
The reference will be added automatically. Note that normal assembly-probing rules apply when your dynamic assembly executes, so in order to find the assembly. You must (one of):
ship static.dll alongside dynamic.dll
put static.dll in the GAC (but please: don't do this!)
run dynamic.dll in a custom AppDomain with a custom probing-path configuration that lets static.dll be found
handle AppDomain.AssemblyResolve to provide static.dll
use something like ILMerge to fuse static.dll and dynamic.dll

How come I don't need to reference "System.dll" to use the "System" namespace?

I am working on an assignment that specified "Do not use any external libraries". So I created a c# application, and the first thing I did was remove all the dll's references by default... including "System.dll".
However, I can still add this to my code:
using System;
using System.IO;
I was just curious as to how come I do not need to have System.dll as a reference in my project to do this. Thanks!
mscorlib.dll includes items in both those namespaces.
You need to right-click your project > Properties > Build > Advanced... and check "Do not reference mscorlib.dll" to remove this reference.
Different assemblies can contribute to the same namespace.
Even if you don't reference System.dll, you are still referencing (implicitly) mscorlib.dll which contributes many types to the System namespace.
These references are probably defined in your Web.config or the Machine.config file so they're included by default.
These are the default libraries.I think your question is that "Dont use third party dlls"
Another thing to consider is, if you're compiling directly through the command line, a default set of switches, including default library references, is parsed by the compiler through the default response file (csc.rsp), located in the same directory as the compiler. The fact that you are able to import namespaces from the Base Class Library without explicitly referencing them at compile time is due to the fact that their containing assemblies are included in your program by default. To change this behavior at the command line, you can use the /nostdlib switch to force it not to include mscorlib.dll, or you can use /noconfig to have it ignore the entire default response file altogether. Also, I'm not too sure what you mean by system.dll, because the namespaces you mentioned are contained within mscorlib.dll. Also, I think by "external library", your instructor must have meant any 3rd party assemblies that would assist you in solving the problem. Anything that comes included with the .NET SDK would be more of a framework library. Unless your teacher is really harsh and wants you to reinvent the wheel :P

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