I've run into a slight issue - I'm writing a program that loads DLLs, each of which contain a class which inherits from a class existing in a library referenced by both the loaded DLL and the "host" program that is loading the DLL. The issue here is that, when I try to load and cast to the superclass:
var assembly = Assembly.LoadFrom(dllPath);
var type = assembly.GetTypes().FirstOrDefault(x => x.IsSubclassOf(typeof (MySuperclass)));
...
Although both are referencing the class containing MySuperclass, since the dll is referencing the built class library (a separate file from the class library file the loading program is referencing) IsSubclassOf never returns true, because it considers the two classes to be different as they come from two different assemblies.
Furthermore, if you try casting a created instance of the loaded class to the superclass type, it can't do it since they're not the same (different assemblies).
So, my question is: how do you handle loading assemblies which reference common code, so that c# recognizes that you're loading a class which inherits from a common superclass?
You simply must use the same assembly files (even if they are identical) if you want programs to work together using common code. Here's how I solved the issue:
The program is loading a DLL from a subdirectory of its own.
Folder structure:
MyApp Folder -->
MyProgram.exe
CommonDependency.dll
Submodules ->
MySubmodule.dll
To get MySubmodule to use CommonDependency.dll within the next folder up, it's quite simple. Configure Visual Studio to not copy these dll dependencies to the build folder. Next, create an App.config in Visual Studio and add the following:
<configuration>
<runtime>
<assemblyBinding>
<probing privatePath="../"/>
</assemblyBinding>
</runtime>
</configuration>
This will tell the system to search for the assemblies in the parent folder ../ - if you want to have multiple folders, perhaps a separate dependency folder (relative to the location of the .dll) you can use ; as the delimiter - ../;../bin/; - the program will search these locations for the dependencies.
The ancestor class (superclass) must come from the same assembly for any chance for the loading code to work with descendants as a superclass reference.
Related
I'm writing a plugin architecture for testing purposes (I know there are frameworks to do that), this is how I've done it right now:
I have a common library shared by the main program and the plugins dll, I'll call it PluginBase assembly.
That assembly is referenced in a plugin MyPlugin which is in the folder Debug\Plugins.
It is also referenced in the main program, which is in the folder Debug.
The problem is, when I dynamically load the interfaces contained in the PluginBase, it gets the interface's Type object from the assembly located in Debug\Plugins.
But when I try to use the same interface (IMyPlugin) in the main program, it loads it from the PluginBase assembly located in the Debug folder.
And that causes invalid cast exceptions when I try to use the interface in the main Program.
The folder structure:
\Debug\MainProgram.exe
\Debug\PluginBase.dll
\Debug\Plugins\MyPlugin.dll
\Debug\Plugins\PluginBase.dll
The scenario of the loading is:
The ServiceProvider loads the plugins definition, ans also dynamically loads the interfaces contained in the PluginBase assembly (located in Debug\Plugins)
The main program calls the ServiceProvider to get a specific interface (but this time loaded from the Debug folder)
The types of the interfaces don't match (even if they are the same)....
I tried to locate the PluginBase dll in the Debug folder, but then I get compilation issues since the PluginBase dll gets copied to the Debug folder after the compilation of my plugin project.
Also I don't think this is a clean way to do this.
Is there a way to overcome this problem ? (like perhaps setting a build order in a way?)
I have a .Net class library that contains many different namespaces and multiple sub-dependencies (referenced assemblies).
Sometimes a project references only one specific namespace, sometimes just one single interface, of such class library but still upon compilation all sub-dependencies (dlls) are copied into my project assembly folder (\bin folder).
So if class library MainClassLibrary references subLib1, sublib2, and sublib3 and when I create a new project that references MainClassLibrary then subLib1.dll, subLib2.dll, and subLib3.dll are also all copied into the binary folder of my project even if I only use an interface definition in a segregated namespace within MainLibrary that does not depend on any of the sub dependencies.
Is the only way to split up the class library into smaller pieces or is there a better, easier way?
even if I only use an interface definition in a segregated namespace within MainLibrary
That is the reason that sometimes only one or a handful of interfaces are put into a separate assembly (Project).
But in general, focus on minimizing the logical dependencies and don't worry to much about how many DLL files are copied.
And as #Alexei mentioned in his comment, this (automated) proliferation of DLL files is the solution to DLL Hell.
In C# .NET 4.0 I am creating a class library / DLL that I plan to reuse in many other projects. This class library will use several DLLs itself. For example, the class library I am creating may reference several DLLs like:
ServerConnectorLibrary references:
Lib1.dll
Lib2.dll
Lib3.dll
When I build this, I get ServerConnectorLibrary.dll as the output in the bin\Debug folder.
What I want now is to use this ServerConnectorLibrary.dll in other projects. However, when I add the DLL to my new projects and run I get the following error:
FileNotFoundException: Could not load file or assembly "Lib1.dll".
If I add Lib1.dll to the bin\Debug folder of my new project, the problem is not solved.
You may be able to combine all of your dependencies into a single assembly. Here is an old example on CodeProject.
http://www.codeproject.com/Articles/9364/Merging-NET-assemblies-using-ILMerge
There is also a StackOverflow thread here...
How do I merge multiple .net assemblies into a single assembly?
Otherwise, make sure the properties for each dependency is set to copy local and then include the dependencies along with your library. These are DLLs, so they are dynamically linked at run-time, unlike older C++ and C libraries that might be statically linked.
I have a project ProjectA in which I am keeping utility classes. I want to use this project in multiple solutions so I do not have to copy files, link files and update files every time I make changes in classes of Project.
But there seems to be a problem: if I am referencing ProjectA in ProjectB, the compiled application of ProjectB can not run unless there's a compiled application from ProjectA next to it. So if the output of ProjectB is ProjectB.exe, ProjectB.exe gives an error upon execution if ProjectA.exe is not next to it. Why is that? I just want to use namespaces from ProjectA in ProjectB, I do not need ProjectA to depend on a compiled version of ProjectB.
Can anyone tell me how to reference ProjectA in ProjectB without needing the output of ProjectA to run the output of ProjectB?
You probably need a shared dll.
You have created utility classes in project A out because they are shared all across project A (Application A?), now you have introduced project B (Application B) and as you state it needs to get hold of the code from projectA.dll/exe.
So create a new project in your solution (Ab.Shared.dll maybe:-)) and move your utiilty classes into it. You can now reference that dll from both project A and project B.
Update: Just read about your comment about sucking code out.
The shared dll is the most common way of sharing the code about, but there are other ways. Theoretically you can simply "include" the same *.cs files in both projects and share them that way (use the drop down on the Add existing item dialog and select Add as link) . However in practice it becomes more awkward maintaining this scenario so most people use a shared dll.
Namespaces are not restricted to one assembly - you can use the same namespace across several assemblies if you wish, and one assembly can contain as many namespaces as you like.
If you are referencing a class/type from another assembly, then that assembly must be present (or locatable) when you run the original assembly. If all you are doing is coding then a simple project reference in your solution will do the trick. If you don't have the source code to Project A then you will need it in its compiled form - without it the CLR cannot inspect it and know what it contains.
In that case add the ProjectA compiled dll in your bin folder and add the reference to that dll from your other project. Do not add reference to your ProjectA project.
When you add reference to the project using Visual studio, Add Reference -> Projects, then it requires the project to be compiled and it copies the dll/exe to the other project bin folder.
Open your csproj file in text editor and insert xml:
<Reference Include="AssemblyName.dll">
<HintPath>$(EnvironmentVariable)\bin\AssemblyName.dll</HintPath>
<Private>False</Private>
</Reference>
If I understand correctly, you have code in ProjectA.exe that you want to use in ProjectB.exe, but at run time, you'd like to run ProjectB.exe without requiring the user to have a copy of ProjectA.exe.
This is not possible. When you use a type from another assembly, that assembly is loaded at run time. The type is not copied from ProjectA to ProjectB.
It sounds to me like you should extract the common utility classes into ProjectUtility.dll, and then reference that from both your ProjectA.exe and ProjectB.exe applications.
EDIT: ILMERGE might be the way to go. See Linking statically in C# for more information.
I'm building Web project using TFS 2010. The project contains Silverlight client and .NET/C# server side. Both of these (client and server) are referencing one 3rd party library for which we have Silverlight and .NET version, but both versions use the same name. The problem is that msbuild with outdir property specified puts all the libraries to one flat hierarchy in output directory so one library overwrites the other.
I know that one solution would be to modify build template and not specify outdir, but this brings problems with other parts of the build template (I had problem with unit tests and I read about people having problems with putting output to _PublishedWebsites).
Another workaround would be to rename that library/libraries so the names will not collide. But this will not be solution if there is a lot of such libraries.
I'd like to find some clean solution. Do you know about some elegant way how to solve this?
According to Microsoft there are (at least) three ways of referencing assemblies:
install the assembly in the GAC
specify the assembly in the application configuration
or use the AssemblyResolve Event
The GAC is no option here, as you would have the same problem (same names).
Using the AssemblyResolve Event and then use Assembly.LoadFrom would possibly a way of doing it, but easier would be imho ...
... to do it the second mentioned way: specify the assembly in the application configuration. Here you basically edit the App.config like so:
<configuration>
<runtime>
<assemblyBinding xmlns=”urn:schemas-microsoft-com:asm.v1″>
<probing privatePath=”bin;Silverlight;ParentFolder\SubFolder;”/>
</assemblyBinding>
</runtime>
</configuration>
and the application will search for the assemblies in specified directories.
So, you could create specific folders (possibly "NET" and "Silverlight" or the like), copy the respective assembly into that folder and probe for the assembly in the proper folder as described above.
Considering that when no reference is specified in the application configuration the application will be looking into either the same folder as the referencing assembly or into a folder with the name of the referencing assembly, you could also simply create 2 folders with the same name as the respective application (say "Client" and "Server" if they are called "Client.exe" and "Server.exe") and copy the proper assembly into that folder. In that case there would not even be any need to change the application configuration file.