Using Global Assembly Cache (GAC) - in the way it was designed to - c#

Is the following solution the only possibility to use libraries from GAC in code?
Assembly lib = Assembly.Load("MyLibrary, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=31f5625abd53197f");
Console.WriteLine(lib.GetType("MyClass").GetMethod("Start").Invoke(obj, null));
I am a little bit confused - I've read quite much about GAC and I know how to sign an assembly, intall and uninstall assembly in GAC, but have no idea how to use it, and how does it help programmers (except that it stores different versions of same library safely). I wish I could normally create classes, not beeing forced to invoke methods presented above.
I don't want any work-arounds such as: "change windows registry" because I don't think GAC was designed for such manipulations. I want a simple answer: what the GAC is for, does runtime environment use it somehow?
What is the point of using GAC, when the code gets really ugly and difficult to manage? Or maybe I am missing something? Maybe I should manually copy an assembly into my local folder? But I heard it's also hard to do.

The GAC is there to help you have multiple versions of your (that's what the public key is for - preventing name clashes) assemblies installed side-by-side, and available to the whole machine, not just your application directory.
So yes, accessing assemblies from the GAC using the version number is pretty much exactly the way the GAC was designed for. ;-)
btw: You should not dynamically load stuff when you don't have to.
IOW: If you already know the class name and assembly version, you could just reference that assembly and skip the rather dramatic performance penalty of not only loading an assembly dynamically, but also invoking methods through reflection. (Instead of e.g. reusing them via interfaces or delegates)

If your assembly has been ngen'ed or GAC'd, then the application will use that automatically, if everything (hashes, etc) matches.

If you reference the assembly in your project, you can use it like a normally referenced DLL that is not in the GAC.

Related

Which assembly executes the code?

I'm working on a .net project, which is using third party .net DLLs. Some of this DLLs are using common DLLs (e.g. Microsoft.Practices.EnterpriseLibrary.Logging). Now we want to use the same common DLLs in a newer version. We are not allowed to use the GAC (politics).
We have separated the parts in different directories.
Third party \ Third party.dll
old common (Microsoft.Practices.EnterpriseLibrary.Logging.dll)
Our libs \ our lib.dll
new common (Microsoft.Practices.EnterpriseLibrary.Logging.dll)
Surprise, Surprise, it did not work. In our dll an error is thrown saying, some option is not valid. Yes, I did not find it in the old common, but in the new. So, I guess, the wrong executable was taken.
In Visual Studio (2015) we have enabled the "Spezific Version" in the reference, and in the Debug / module windows, both DLLs are loaded.
Edit: All Dlls have strong names.
How do I determine which DLL was executed (stepping with F11 just jump to the catch block)? How do I force using the correct DLL?
(The architecture loads first the third party DLL, then our own dll. This is not changeable without a few years rewriting...)
You can use assembly binding redirects and hope the universe doesn't break (there's no guarantee the newer DLL is backward compatible) or you can strong name the dlls.
Why? .NET generally does not allow you to load the "same" assembly more than once in the same AppDomain, unless it is strong-named. What's strong naming? It is a form of identity and digital signing that consists of:
Assembly filename
Assembly version
Assembly culture
Assembly public key
When it's strong-named, both dlls run side-by-side in the same AppDomain within the same process with perfect backward compatibility.
Alternatively if you don't want to use strong-naming (because many files may require signing) or binding redirects, you can always create additional AppDomains and load a version of the dlls into each domain.
Though it gets around the problem of fiddling with files, it does require considerable rework of the rest of the app making it an arguably bad choice at this point in your development.
EDIT: I see now you are using strong names on both.
How do I force using the correct DLL
To distinguish between the two types in the exact same namespace, you might have to create an alias for the newer assembly in your dll reference. Tell me more...

How to replace a loaded assembly

Ok so I have a pretty unique problem here. I'm getting an error basically because I'm referencing the latest version of a dll which I still want to keep references to by default because most of the code in my project is supposed to be using this dll. The error occurs because it's trying to use an object that is only available in the older version of the dll. So I want to use this older version of the dll for this particular section of code. I have tried to load this older version of the dll using Assembly.LoadFrom(pathToAssembly) but it still appears to reference the newer version of the dll. Does anyone have any ideas on how I can replace the reference to this dll to the older version?
Only real option you have is to make sure that assembly is strongly signed, make sure there is no assembly binding redirect to newer version and than manually (with Assembly.LoadFrom) load second version into your appDomain. This way code will be able to use precise version of assembly and both assemblies can be loaded into same appDomain at the same time.
Note that this will lead to complete nightmare if you ever need to pass references to such objects between pieces of code linked against different assemblies.
If you want extra painfun - load both assemblies from bytes and use reflection to construct types for each version...
I'd strongly recommend avoiding all the pain by loading code using different versions of assembly to at least separate appDomains, but preferably to separate processes. If you still decide to take adventurous path of loading multiple versions of assembly to same appDomain make sure to read all aassembly loading blog post from https://blogs.msdn.microsoft.com/suzcook/2003/09/19/loadfile-vs-loadfrom/

How can we access a binary from GAC irrespective of .Net Framework

Initially, we were working on .Net Framework 3.5. Hence the GAC path was hardcoded in code as
C:\Windows\assembly\GAC_64\{0}\1.0.0.0__008145f79b9aec14\{0}.dll
Later we migrated to .Net Framework 4.0. Now the required path should be
C:\Windows\Microsoft.NET\assembly\GAC_64\{0}\v4.0_1.0.0.0__008145f79b9aec14\{0}.dll
Currently the problem can be fixed by putting the second path in my code. But when Microsoft releases its next set of frameworks, it might fail.
So i wanted to know if there are any ways in which we can access GAC binaries independent of .Net Framework.
Any comments on this will be helpful. Thank you
If you want to load an assembly from the GAC, load it by using its fully qualified name:
Assembly.Load("SampleAssembly, Version=1.0.2004.0, Culture=neutral, PublicKeyToken=8744b20f8da049e3");
If it's found in the GAC, it will be loaded from there.
You should never ever hardcode the path of the GAC anywhere. It could change at any time, even between service packs or patches, and it's an implementation detail that you cannot rely on.
DO NOT HARDCODE THEM
I guess you do not need to load the assembly using its path in the GAC (there would be a big big Why for this) so maybe you have to inspect the binary file by hand without loading it (for example to list available assemblies or to inspect their metadata).
If you need to access the GAC do not rely on paths, it'll be the hell for you (Windows directory changes, GAC structure isn't trivial and effective path depends on environment, assembly type and more).
There is an unmanaged API to work with this: look here on MSDN for reference. For example to get the path of the GAC you may write:
GetCachePath(ASM_CACHE_GAC, pPath, MAX_PATH);

Plugin Situation: What to do with dependent libraries?

I have a MEF-based application which uses adapters to process files. It uses configuration files to determine which directories to watch and which adapter to use to process each type of file. Plugins take the form of a .dll that implements a common interface.
Each .dll requires its own set of dependent libaries. For instance, plugin1.dll might need to use apilibrary.dll and xmllibrary.dll. It is also possible that at a later date I might want to add plugin2.dll, and plugin2.dll might use xmllibrary.dll as well. These dependent libraries are updated regularly, so I can't count on plugin2.dll using the exact same version of xmllibrary.dll used in plugin1.dll.
I'd like to compile each plugin to one .dll file that invisibly includes within itself all of its dependent libraries, which seems like one way to solve this problem. Alternately, I'd like to figure out how each .dll file can look for its dependent libaries in a subfolder, which I believe would also reduce the possibility of versioning conflicts. Or maybe there's a dead simple solution to this problem that I haven't even considered (which is always very, very likely).
Any thoughts?
You should probably try to get this to work with standard .NET loading rules. However, if you do need to control exactly how assemblies are loaded and which versions are loaded, this blog post shows how: Using Loading contexts effectively
I guess you need to weigh up deployability vs. maintenance. The simple solution is to use a tool called ILMerge. ILMerge takes your project output and can take other assemblies and merge them together. This enables you to wrap up all of the assemblies that your plugin is dependent on, and merge them into a single assembly. Optionally you can do things like re-signing with your public key, etc. Here is a good read: Leveraging ILMerge to simplify deployment and your users experience by Daniel Cazzulino.
But while that is good, what happens if a new version of the referenced assembly is distributed that corrects bugs in that which you have embedded? By the rules of Fusions assembly loader, when it loads the types from your referenced assembly, it will see that they have already been loaded, so there is no reason for it to load the updated version. This would then mean you need to recompile your plugin and merge the newer referenced assembly again.
My question would be, is it really that important to ensure a specific version is used? If a newer version provides an updated implementation (that doesn't break backwards compatibility) then surely this should benefit all plugins that need to reference it?
As for as how assemblies are loaded in reference to each other, have a read of Understanding .Net Assemblies and References, which is an invaluable piece of information.
MEF uses standard .NET assembly loading, and everything's loaded in a single AppDomain. You have very little control over how dependencies are loaded - as they just get loaded automatically by the CLR when the assembly is injected via MEF. Normal CLR assembly loading rules apply when using MEF, so dependencies will be loaded as if they were a dependency of your application - no matter where they're located or referenced.
For the most part, if the plugins and their dependencies are properly written, you most likely will not need to worry about this. As long as the versioning in the dependencies is correct, it will likely just work.

c# - can you make a "weak" assembly reference to a strong named assembly

For various reasons i would rather not use strong named (signed) assemblies in my project. however, one of the projects is referenced by a sharepoint web part which means it must be signed.
is it possible to have this assembly signed but when I reference it from other projects, to do so using a non-strong reference. this would give me the advantages of having a non-signed assembly for the rest of my code but still allow it to be loaded by sharepoint.
The simplest way to do this is probably to have two different project configurations - one of which builds a strongly named assembly and one of which doesn't. Obviously you'll need to be careful how you build and reference the assembly, but that goes with the territory of having conflicting requirements.
Just keep building your project w/o strong names. When you need to deploy it to Sharepoint, use a tool to sign it after it is built. Here's a tool that does exactly that:
http://signer.codeplex.com/Wikipage
You can also do it manually, but it's a PITA:
http://buffered.io/posts/net-fu-signing-an-unsigned-assembly-without-delay-signing/
This is the OP but I don't have an OpenID login so I guess I can't reply as myself.
Thanks for both the responses. I think either would have worked but the situation turned out to be a bit more complex. I've documented my findings here in case anyone else is interested.
In fact sharepoint references assembly A and assembly A in turn references assembly B.
I can build assembly A and B both unsigned with no problem, but then if I want to sign A, I have to change the project itself to reference the signed version of assembly B.
Although there might have been a way to do this, we decided the possible DLL conflicts and configuration control problems with having different sets of DLLs with the same name were not worth the hassle.
So we have decided to sign both these assemblies in all builds, refactoring code into different assemblies where necessary to make sure that only the minimum amount of code is in the signed ones so they are less likely to change.
Tim

Categories

Resources