I have an application that loads dlls dynamically. The application and the
dlls use a Functions.dll that can be a diferent version for the application an
for each dll, but in execution the application and the dlls all use the same
dll version (the one used by the EXE) and share the static variables...
How can i force them to use their own Functions.dll(n-version)?
-Details:
I tried loading the dlls by "Assembly
dll = Assembly.LoadFile(" and by
"Assembly dll=domaindll.Load("
In Functions.dll, al the methods and objects are Static
I use Functions.dll "statically" by referencing it throught VS in all
cases not dynamically
The dlls and Functions.dll are developed in C# too
-Folder Estructure:
Application:
Application.EXE
Functions.dll(version 1.2)
DLLS:
EXAMPLEDLL1:
EXAMPLEDLL1.DLL
Functions.dll(version 1.1)
EXAMPLEDLL2:
EXAMPLEDLL2.DLL
Functions.dll(version 1.0)
EXAMPLEDLL3:
EXAMPLEDLL3.DLL
Functions.dll(version 1.2)
You can enforce binding to a specific version of a DLL by strong-signing it. You can also try setting "Specific Version" to true on the reference properties, but as far as I'm aware that only affects compile-time binding and a different version can be loaded at runtime if the assembly isn't strong-signed.
This should get you started: Strong-Name Signing for Managed Applications
Be aware, though, that any types declared in this dll will not be type-equivalent to the same type in a different version of the assembly. For instance, if I declare a class called Foo in Functions.dll, then an instance of Foo from version 1.0 won't be the same type as an instance of Foo from version 1.1. As far as the CLR is concerned, these are completely different types.
If all you have are static functions in the assembly and no types are defined, then you should be OK. Otherwise you need to look into a different approach.
To be able to do that I think you'll have to load your (Example) DLLs into separate AppDomains. Making cross-AppDomain calls incurs a bit of a performance penalty, but that is kinda unavoidable in the scenario you highlight.
At the end I solved it renaming the Functions.dll to match the EXAMPLEDLL that uses it....Ex: Application.EXE-->FunctionsApplication.dll EXAMPLEDLL1.dll-->FunctionsEXAMPLEDLL1.dll Thanks for the answers anyway..
Postdata: In another case where I could sign correctly the dlls i think Adam Robinson answer would be the correct one(and jerryjvl the second anwser).
Related
I have two projects:
ProjectMain (class library)
LibraryProject (class library)
ProjectMain is a class library that should only be compiled as a singular library, no referenced libraries. I require a static class reference from LibraryProject BUT I don't want the LibraryProject assembly to be compiled together with the ProjectMain assembly.
I've tried 'link references' in visual studio but this is no solution as the library assembly is always compiled with the main assembly.
There are clear standard solutions to this issue but I am severely limited by the existing implementation requirements. Only one DLL can be compiled without any of the dependent assemblies being in the execution folder, GAC, private path, reflection etc.
The exact limitations are as follows:
Assembly executed in a sandbox from a third party provider, it only supports adding a single assembly with no direct references/reflection etc (it's horrible but my hands are tied)
We would like to handle the code organisation as best possible which means following standard best practices, unfortunately, due to the above limitation that's proving difficult.
What I would like to know is if there is a way to reference a class within another project without also compiling/using that referenced classes assembly. Possibly a method where the compiler 'embeds' the referenced class at compile time.
If your sandbox does not allow loading other dlls in AppDomain, load it yourself by embedding it. You can use Costura.Fody for this purpose, it is easy to use/install, just reference it from nuget.
Of course, embedding it in every scenario is madness and often comes with completely obscure bugs, which often solvable only by enabling traces in regedit.
So, in your case I would create two projects:
MyDll.csproj //it is my original project, with perfect code design and etc. Lovely.
MyDll.Sandbox.csproj //this one is the same as MyDll.csproj, except it is compiled with additional Costura.Fody reference, into single dll (every reference is put inside)
This way you just need to maintenance that MyDll and MyDll.Sandbox files are the same.
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 have a project which needs to indirectly use three different versions of a third-party library. These versions are incompatible with each other, so I can't use a binding redirect - it has to be the exact .dll file. (The libraries are Spire.Doc, Spire.XLS & Spire.PDF; the Spire.PDF DLL is referenced by all three)
I have separated the three components into individual wrapper projects, and created classes which wrap direct references to anything in the libraries. However, this doesn't solve my issue: the 'consuming' project still has to copy all of the libraries to the bin folder in order to run. The build process doesn't know which version to copy, and so just copies the latest one. This gives me runtime exceptions due to the wrong DLL being present.
What I've considered/tried:
Adding a binding redirect to a specific version (runtime exception because the exact version of the library is not found)
Using a post-build step to merge the wrapper projects (again a runtime exception complaining about the absence of the library DLL)
Creating separate console applications for each part of the application, then invoking them in a separate - this is a complicated last resort that I'd really rather not do!
I have read that extern alias might be able to help - but as far as I can tell, you can only distinguish between assemblies with different names. The Spire.PDF library has the same name in each project (and the same signed public token).
How can I use these three separate versions of the library independently in the same solution?
Edit:
This issue is slightly different to the suggested duplicate because I don't have the ability to change any code in the dependent libraries. Spire.Doc relies on a different version of Spire.PDF to Spire.XLS
In your consuming project (Project A), create a common interface (ISpiroPdfAlex) that encompasses all the functionality that the 3 versions of your external assembly provides (and you use). You cannot reference anything in Project A from these wrappers in any way, otherwise you'd create a dependency, which is what you're trying to avoid.
Have all 3 wrapper projects import Project A and implement ISpiroPdfAlex. This will give you the ability to call each of the 3 different versions through the same API.
After this, create a subfolder under Project A for each of the versions (so 3 subfolders total) - since Project A has no reference to any of the external assemblies, it cannot load them by itself - you'll have to manually load them when you need the right version. Since your external DLLs may have dependencies with the same name, they cannot all be in the same folder (as you wrote), this is why you need the subfolders.
At run-time when you need one of these versions, you can call Assembly.LoadFile to load a specific version of your assembly from the specified folder and then you can either use Activator.CreateInstance or dependency injection to create an instance of a class that implements your interface. Once you have the instance, you're free to call any of the functions and you'll get version-dependent behavior.
Edit:
OP mentioned in a comment that it's not his code that has the dependency on different versions of the PDF library but the other 3rd-party Spire libraries that his code depends on.
In this case, the 3rd-party code cannot be modified to support dynamic loading of assemblies and they already have a binary dependency. It's not possible to load different versions of the "same" assembly into the same process, especially that you mentioned that these versions are not even backward-compatible with each other.
The only solution I can think of in this situation is to break out all dependent functionality into separate console applications (one for each different version) and call those separate .exe-s through the command-line.
To pass information, you can either pass data directly on the command-line or through stdin. Alternatively, you can just pass the name of a temporary file that has all data necessary to do some processing. To get return data back from the console process, you can either read its stdout or use the same / different file.
This way your main process never loads any of these assemblies and has no dependency on them - each console application has a dependency on just one version so there's no collision.
I have a semi-large C# .exe project in visual studio 2010 Ultimate, and I would like to convert it to a DLL class library. Is there an easy way to do this that doesn't involve creating a new class library project? Thanks beforehand.
Project > Properties > Application tab, change Output type to "Class Library".
For the record, this isn't actually necessary. An EXE project works fine as an assembly reference. Assuming classes were declared public, something you might have to fix anyway to make them work in a library.
In .NET, an .exe and a .dll are both legal as references. This is because in .NET, there exists two type of assemblies:
process assemblies - known in public as executables, or exe
library assemblies - known in public as dll
An assembly in .NET holds many modules, that in turn holds one or more classes (the guideline is one class per module). These modules is turned into IL code at compile time and JIT'd at runtime.
The important part for both types of assemblies is that each assembly holds meta data like
modules
methods
types
there exists in an assembly. And because of that the runtime, and compiler, can easily determine how to fx call a certain method in a process assembly.
I think, without being an expert on the subject, that the major difference between process assemblies and library assemblies is that process assemblies holds some extra code, telling the runtime how to load, and what to load.
Go into My Project in your solution, select the Application tab, and change the Application type to Class Library.
right click on project and goto its properties and look for the Configuration type in Configuration Properties then change it to .lib from .exe ... this changes the application type from executable to library
I've been trying to crack this one over the last couple of weeks and have not found a good solution yet; hopefully I can get an answer here.
I have two assemblies (ZA & ZB), both of which point to a common project/dll (ZC) but which could be on a different version (i.e. same dll name, same namespaces, some classes may be different). Each assembly works by itself, however, if one is loaded by the other at runtime (e.g. A loads B), then I cannot get it to work. Need some help.
Here's the setup:
ZA depends on ZC (common) version 1.1
ZB depends on ZC version 1.0
ZA needs to load needs to load something in ZB (which depends on ZC), at runtime.
ZA is the master app.
Under its bin directory, there's a plugins directory plugins/plugin-ZB under which I would like to place all of ZB and its dependencies (ZC).
Here's what I've tried so far:
Assembly.Load() using same version of dll - worked fine.
Assembly.Load() using different versions of dll - ZB loads, but when the method runs, I get a method not found exception.
AppDomain.Load() got a file not found error; I even used the delegate to resolve assemblies.
Some details regarding ZC:
- some methods are public static (some are not). E.g. Log.Log("hello");
- some may return values (primitives or objects).
- some methods are non static (and return values).
Help? - TIA
m_Assembly1 = Reflection.Assembly.LoadFile(IO.Path.Combine(System.Environment.CurrentDirectory, "Old Version\Some.dll"))
m_Assembly2 = Reflection.Assembly.LoadFile(IO.Path.Combine(System.Environment.CurrentDirectory, "New Version\Some.dll"))
Console.WriteLine("Old Version: " & m_Assembly1.GetName.Version.ToString)
Console.WriteLine("New Version: " & m_Assembly2.GetName.Version.ToString)
m_OldObject = m_Assembly1.CreateInstance("FullClassName")
m_NewObject = m_Assembly2.CreateInstance("FullClassName")
From here on out I used late binding and/or reflection to run my tests.
.NET: Load two version of the same DLL
Apart from Jonathan Allen excellent advice, a more "classical" way to resolve the problem is by loading the 2 versions in 2 different AppDomanis. You can then use .NET Remoting to make the two AppDomains comunicate. So ZA should create a new Appdomain, Load in this AppDomain ZB and invoke some operation in ZB via Remoting.
Note that .NET Remoting has some requirements on the classes that you want to use (inheritance from MarshalByRef), and creating an AppDomain is an expensive operation.
Hope this help
I have had two versions of the same assembly loaded at the same time. It happened with a scenario just as you describe it.
You have to convince the runtime to load the same version of ZC for both ZA and ZB. I have found two ways to do that:
Use a bindingRedirect element in your App.config file. There are some details in this question.
Use the AppDomain.AssemblyResolve event. There are some details in this answer.
The only problem with AppDomain.AssemblyResolve is that it only triggers when the runtime can't find the requested version. If both versions are available, then you'll have to use the bindingRedirect. I have used the AppDomain.AssemblyResolve event and then added a safety check that makes sure the right version was loaded by looking through the assembly's referenced assemblies collection. If it isn't, I complain to the user that an old version of the library is lying around and tell them where it is.