Missing DLLs from a class library that uses separate DLLs - c#

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.

Related

Converting a C# class I created inside a project to a separate reusable class

I'm not new to C# programming, but I suppose I'm new to programing "the right way" in C#. I've worked in C on embedded devices for years and have written desktop apps to support them. First in VB6, then in C#.
I recently started making better use of classes for reusing code (and for instantiating more than one instance of the class in a program). For example, I "wrapped" a UART interface with some additional functionality so I can use the same code for multiple ports by creating an instance of the class for each one.
It is in a separate file, but still in the same program namespace, so when I want to reuse it, I have to copy the file and change the namespace to the new project.
I'm sure there's a way to create it such that I can just reference it like everything else with either a "using..." reference at the top of the program or with a "Project | References..." checkbox. But for the life of me I can't find a good learning journey for this.
Any direction would help.
You want to create your reuseable class in an assembly - this is the equivalent of a dll from your C experience.
To create an assembly, have a separate project of type assembly (instead of exe) . You can reference the assembly from other projects. If your project is in the same solution you can reference the project, otherwise you can reference the compiled assembly.
C# uses a packaging system called Nuget, so you can package your assemblies into "Nugets" which you host in a Nuget Server. You can then use tooling to discover and import these.
Please create a Class Library project and include your class into that project. Make sure your class is public. Once you build this project you'll get an assembly which can be referenced from other projects. See Tutorial: Create a .NET class library using Visual Studio
There are different ways of referencing it.
You can have the class library project in the same solution as the main project. In this case you should add a project reference.
You can copy the compiled *.dll file to some folder in your solution (e.g. Lib) and add an assembly reference.
If this assembly is to be used in multiple projects please consider creating a NuGet package with this library and pushing it to some repository. Then other projects can add a package reference to this package.
Details:
How to: Add or remove references by using the Reference Manager
Install and manage packages in Visual Studio using the NuGet Package Manager
It is in a separate file, but still in the same program namespace, so when I want to reuse it, I have to copy the file and change the namespace to the new project.
Well, it isn't the best practice but (unfortunatly) still a common behavior. So don't worry to much about it.
What you could do to improve it place the file (and other reusable parts) in a seperated csproj.
For example name the project of the type class library and name it VinDag.Tools. Within the project create a folder UART and place the wrapper there. The namespace of the wrapper would then be VinDag.Tools.UART.
From know on you can just reference the class library instead of renaming the file. It's not necessarily required to be the same namespace as the project.
From there you can start considering (private) nugets. This would prevent you from copying files/csproj around.

How to create a dll that includes all the others?

At the moment of creating a project of type "Library of Classes, usually one can generate a dll when compiling, but how could I generate a dll without losing others that I already have included?
I explain with an example: It turns out that Nuget downloaded an S22.Imap dll with the one I worked with, later I generated the dll in the traditional way that I explained in the beginning, but when I wanted to work with dll in another computer, I got errors that were not I found functions that contained the S22.IMAP dll. So to solve this problem, I had to copy the dll of my project, S22.IMAP in an additional way in a specific path of the other computer.
My question is:
How could you generate a dll that includes the ones included in the project you were working with?
All the referred 3rd party dlls (S22.Imap.dll in your example) will be copied to the output folder together with your own dll file (let's say a.dll) when you build your project. That means you should always copy them together (S22 + a.dll) to the place you want to refer them, on another computer/folder/place.
If you really want to make them only one file (although it is not recommended), you can set the S22 one as some "nested resource". Then you will get only one a.dll file and the S22 one is inside the a.dll. See below page for some reference:
Embedding one dll inside another as an embedded resource and then calling it from my code
AND, ILMerge is some tool that can help you do so.
In general, you don't. A DLL is a dynamic linked library, and you would normally only combine static libraries during a build. Here is an answer on the difference between static and dynamic linking.
Typically you would include all the DLLs you need in the installer package. If you use Visual Studio to create the installer, it can detect the dependencies for you. When you run the installer, all of the necessary DLLs are deployed. Nearly all commercial .NET software follows this pattern.
It is possible to merge an assembly into another assembly using a tool called ILMerge. This would be a very unusual thing to do, and could cause issues with intellectual property and code signing, so it is not recommended.

Base project dll reference not found in upper layers

In my current architecture I have the following project organization...
An class library named "MyBaseProject" and different web application projects with reference to MyBaseClassLibrary.
In MyBaseProject I added a 3rd party dll (Newtonsoft.Json)
Now all web projects are throwing the exception "Could not load file or assembly Newtonsoft.Json or one of its dependencies."
I do not want to add the Newtonsoft.Json in all my web projects, what should I do?
See How the Runtime Locates Assemblies.
The most obvious behaviour here is that you have not set the output directory for your projects, and thus they're defaulting to their own, individual locations. Thus, while MyBaseProject references and copies Newtonsoft.Json, your other projects only copy over MyBaseProject. Because of this, the MyBaseProject.dll located in the folder with the other projects does not have a copy of Newtonsoft.Json, and since it's not in the GAC, the reference fails.
The easiest solution is to make all your projects output to the same directory. I'm personally fond of $(SolutionDir)\bin\$(Configuration)\$(Platform). This will ensure that when MyBaseProject.dll is built and carries along any of its requirements, your other projects will be able to get those requirements via the same folder without incident.

How to pack referenced libraries into a new libarary

When creating a new library MyAPI.dll, I am referencing many other (non-standard) libraries such as RestSharp.dll, Newtonsoft.dll,MyUtilities.dll, etc. My library works fine in my development environment because I've downloaded all of those other libraries and they're sitting in my project's bin folder, but as soon as I try to publish that library and use it in a new location, it fails because the referenced libraries cannot be found.
How to I set up my MyAPI.csproj project so that these dlls/libraries get packaged into my published .dll file, and future users of MyAPI.dll don't have to worry about downloading and referencing those dependencies?
Thought this would be simple, but my google-fu is weak today. Setting those external references to CopyLocal = False removes them from the /bin/ directory, giving the illusion that they are getting packaged into MyAPU.dll, but really Visual Studio is just adding them to my Global Assembly Cache (GAC), which doesn't help future users of the API.
There are two options (as far as i know):
ILMerge
Embeded Resource and Assembly.Resolve (see Jeffrey Richter)
First you can use ILMerge, which is comamndline program that can merge multiple .NET assemblies together, creating one output file. It cant merge WPF projects. Can be added to postbuild events to make the merge automatic.
Second is adding library as embeded resource to your project, and then registering to Assembly.Resolve event and loading assembly when its needed from resources. Article from Jeffrey Richter about this method: Jeffrey Richter.
The second method has major drawback, it doesnt work with merging multiple libraries into one (it can only be used for adding libraries to executable), at least in c# without another tool. To add library to library you have to use another tool, which is mentioned in Jeffrey's article comments at second page: (Module initializer injection).The problem with embeding library into other library is that you cant (at least in c#) register to Assembly.Resolve event before the embeded library is needed, so you need to inject the registering to module initializer using the Module initializer injection. It can also be set as build event, which is written on the apge with the tool. It may sounds complicated, but once you set it up its easy.
There is a free nuget package "Costura.Fody" it packs dependency assemblies as resources into your assembly. The solution works with WPF and other managed assemblies.
If the dependency assemblies are not in the executing folder, the packed assemblies are taken automaitcally. It also configures your msbuild targets automatically for packing the dependencies during build. You do not have to add code in your assemblies.
It also lets you configure, which assemblies to pack or not in a xml file.
It uses a combination of two methos:
Jeffrey Richter's suggestion of using embedded resources as a method of merging assemblies.
Einar Egilsson's suggestion using cecil to create module initializers.
You can find documentation here: https://github.com/Fody/Costura/blob/master/README.md
It's not free (well there's a trial) but a friend of mine told me about a program called .NET Reactor, which has the ability to package an exe with dependent DLL's into a single executable, well worth a look.
I would say the next most straight-forward alternative would be ClickOnce, a good tutorial is here.

Referencing a project in another project creates unwanted dependencies

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.

Categories

Resources