Use assembly from a library which has been created through ILMerge - c#

I have created an assembly package using the tool ILMerge.
There is an assembly (lets call it A) which is part of that packaged assembly which is going to be used by a other assembly, which is not included in the package (lets call it B).
Now what I want to do is create a project which references both, the packed assembly and B. Now I would like to do that:
public void Foo()
{
var obj = new Bar(); // Bar is part of `A`
var someFactory = new Factory(); // is part of `B`
someFactory.DoSomething(obj);
// compiler error here, which says I need to reference the assembly which contains `Bar`
}
I made sure that the assembly A, which was included into the package and the one referenced by B are the same.
Is there something I`m missing here?
Update with more Context
We have a datamodel project which has lots of dependent projects (I know this is bad in the first place, but its legacy code :-( ) So I would like to merge all these assemblies to one in order to use that data model assembly more easily in multiple solutions.

B references A, not whatever freaky deaky merged assembly you have concocted. It may contain all of the types of A, but it is not A -- assembly identity matters. MyMergedPackage.Bar is not A.Bar, even if they use the exact same type name down to the namespace.
There are multiple possible solutions.
First and most obviously, you could simply merge B as well. In a typical ILMerge scenario, you merge all assemblies (including the main executable) into one glorious singularity, so you don't have this problem. I'm assuming you have good reasons for not doing this.
You can simply call your merged assembly A, even though it's A plus lots more. If A has a strong name, you'll need to give that same name (version and all) to your merged assembly. This will keep B happy, which may be enough, but it won't work if you start adding multiple assemblies that want a piece of the whole (you cannot simply copy A around under different names since the types will not be recognized as the same).
If your version of .NET is sufficiently recent, you can create a new assembly A that only contains a type forward for Bar to your new assembly. This A would simply be a placeholder for the original and only distributed to keep B and assorted friends happy. If you have lots of types this way, this is awkward enough that you want automated help. I'm not immediately aware of any. It also rather defeats the point of merging in most scenarios, since you'll end up with multiple assemblies again anyway.
At compile time, simply use the separate assemblies. At deployment, replace them all with your merged assembly. Sort things out in code with a handler for AppDomain.AssemblyResolve to fix up the actual type load at run time (simply redirect all unknowns to your merged assembly). This may require some careful tinkering to ensure the event fires before the runtime needs to look up any of the referenced assemblies (static constructors can especially spoil your fun here).
Disclaimer: I have tested exactly none of these solutions; if one doesn't work, please keep me posted so I can fix this answer.

Related

Is it possible to develop a .NET library with optional reference/dependency and still benefit from IntelliSense/typing?

Let's say I want to write a library and it should invoke OptionalLibClass.Run() if such method is available. However the assembly is big (like SkiaSharp) so I do not want to include it with my library, in case the end developer only need other features.
I know it's possible to use System.Reflection but you lose the benefit of Intellisense and static typing as well as getting a performance hit (though pretty minor IMO, usually it's not a problem).
Expectation:
Add OptionalLib as a reference. Still it should be optional: user should not have to install OptionalLib if they install MyLib from Nuget for example.
Write the following code in the library:
using OptionalLib; // .NET should be able to see this namespace
// ...
if (OptionalLibAvailable()) // How to implement OptionalLibAvailable?
{
OptionalLibClass.Run() // IntelliSense should be able to show me OptionalLibClass
}
End user (developer) doesn't need to do anything beside referring to OptionalLib if they want to.
Note that there may be multiple optional libs.
Possible Workaround:
While typing the questions, I thought of a few solutions though they are not as simple as I would like:
Make an interface IOptionalRun for example. However, end user has to provide their own implementation.
Following above workaround, add a separate MyLib (without OptionalLib) and MyLib.OptionalLib (with OptionalLib) that provides an IOptionalRun implementation. I think this is the best workaround so far and the closest to my expectation but we still need 2 separate assemblies and the user has to register the interface somehow. This workaround has a problem when there are multiple optional libraries and we want users to have any of their combinations (for example: do A if A is available, B if B is available but C if both A and B are available)
Using dynamic: the worst workaround IMO. Technically a shorter System.Reflection solution but still have all its problem.
EDIT: After reading my question again, turn out a solution will probably be the answer to: how to pack/create a Nuget package for a project that contains OptionalLib but it should not be in the dependency list (and don't pack that dll when packing the Nuget package). OptionalLibAvailable can just be a Reflection call to see if OptionalLib assembly is loaded in the current AppDomain.
Edit the properties of that big assembly reference, in the properties window, there is a property Private Assets, set its value to All, then repack your library, you will find that reference has gone from the .nuspec file.

Relation between DLLs and Namespaces in C#

High-level question here:
I have spent a lot of time today educating myself on basic high-level concepts such as APIs, static and dynamic libraries, DLLs and marshaling in C#. Gaining all of this knowledge led me to what seems like a pretty basic question, and probably demonstrates a hole in my understanding of these concepts:
What I know:
DLLs may contain classes which in turn contains various class-members such as methods and fields, several of which I might want to utilize in my program
In C# we use the keyword "using" at the top of the code, to define a namespace we
want to include in our program
What I do not get:
I was under the impression that the actual methods were defined in the DLLs. How does my program find the actual functions that are defined in the DLLs, when all i give them is a namespace? It seems more intuitive to me to have "using XYZ.dll" at top, rather than "using XYZ_namespace".
Thanks a lot for helping me fill in the gaps here.
EDIT: Modified post to be specific to C#.
EDIT 2: For other people that wonder how their C# application actually gets a hold of the types made available through "using namespaceX", this is a good resource (in addition to the helpful posts below): http://broadcast.oreilly.com/2010/07/understanding-c-namespaces-and.html.
Basically the type you would like to use resides in libraries and you have to set Visual Studio to reference these libraries in order to make it possible to "use" its namespace in your code.
DLLs contain many routines / methods we might want to use in our
programs
Partially correct. .Net DLLs contain Classes, and these classes contain Members (Fields, Constants, Methods, Properties, Events, Operators, Indexers).
.Net is strictly OOP, and it does not allow code "floating in limbo". Everything is defined inside classes.
Classes are organized in Namespaces just to keep a naming separation and organization. Think of namespaces as "folders" that contain one or more classes, and that might be defined in one or more assemblies (DLLs).
For example, Classes inside the System namespace are defined in 2 assemblies (DLLs): mscorlib.dll and System.dll.
At the same time, these 2 assemblies contain many different namespaces, so you can think the Assembly to Namespace relation as a Many-to-Many.
When you put a using directive at the beginning of a C# code file, you're telling the compiler "I want to use classes defined in this Namespace, no matter what assembly they come from". You will be able to use all classes defined in such namespace, inside all assemblies Referenced from within the current project.
In C#, DLLs (aka assemblies) contain classes (and other types). These types typically have long full names, like System.Collections.Generic.List<T>. These types can contain methods.
In your References area, you have references to assemblies (this is part of your .csproj file). In a .cs file, you don't need to include any using to reference this DLL, because it's already referenced in your .csproj file.
If you include a line like using System.Collections.Generic;, that tells the C# compiler to look for System.Collections.Generic.List<T> when you type List<T>. You don't need to do it that way, however: you can simply type System.Collections.Generic.List<T>.
I was under the impression that the actual methods were defined in the
DLLs. How does my program find the actual functions that are defined
in the DLLs, when all i give them is a namespace?
The process of finding the correct code occurs through static or dynamic binding and also assembly binding. When you compile the code static binding will tell you if you wrote bad code or forgot to add a reference:
ClassInADifferentAssembly.M(); //Generally this will static bind and
cause a compiler error if you forgot to include a reference to
DifferentAssembly
Unless you are dealing with dynamic or reflection then you have static binding. Assembly binding is a different process. The overall process is complex, but basically assemblies are discovered in the the GAC, current location or you can even handle an event yourself, AppDomain.AssemblyLoad.
So when you add a using statement then static binding can successfully find the correct code in the context. However, you can still receive a runtime error if later the assembly fails to bind at runtime.
DLL is short for dynamic link library. And can be a class library containing classes, methods etc that can all be put under different namespaces.
So first you have to add a reference to the DLL into your project. When that is done, you then use a keyword such as "using" to basically shorten the path to reach the methods/classes in that particular namespace.
Example namespaces
Namespace.Something.SomethingMore.Finally.Just.One.More
Namespace.Something.SomethingMore.Finally.Just.One.More2
To reach classes under those namespaces you can do either of the following
using Namespace.Something.SomethingMore.Finally.Just.One.More;
using Namespace.Something.SomethingMore.Finally.Just.One.More2;
// Now you can access classes under those namespaces without typing the whole namespace
// Like in the row below
Class.GetData();
If you did not have the usings, you would still be able to access those classes. But would then have to type
Namespace.Something.SomethingMore.Finally.Just.One.More.Class.GetData();
Namespace.Something.SomethingMore.Finally.Just.One.More2.AnotherClass.GetData();
DLLs have a collection of functions.
You can calls these functions by one of 2 ways:
link with the DLLs export library (a lib file) or do the link in runtime:
Call LoadLibrary()
Call GetProcAddress and provide the name of the function you want. You'll need to cast it to the actual type (function pointer).
Call the function via the new function pointer.
Pretty simple stuff, just read it on MSDN.
C++ namespaces are just a part of the function name.
You can view what functions are exported from a DLL by using a tool called Dependency Walker.

How can I pass a reference type between Assemblies referencing a common DLL?

High level: I am trying to build a console app (e.g. ConsoleApp.exe) which can perform some processing on any given DLL which references a certain type defined in ConsoleApp.exe.
I decided, maybe mistakenly, that I would need a companion DLL for ConsoleApp which contained the type or types (e.g. ConsoleClass) which were intended to be referenced by arbirary DLLs. To pull this off, as I don't know of a better way, I have two projects in the ConsoleApp solution, one is a class library (Proving ConsoleApp.dll) and the other is a console application which references the class library project.
At this point, I now am able to copy my ConsoleApp.dll to another relatively unrelated project in a separate solution (e.g. OtherApp.dll), reference it, and write a method which consumes a ConsoleClass instance as a parameter.
Now, in order to arbitrarily process this OtherApp.dll, the ConsoleApp.exe loads that Assembly, instantiates the proper class in that Assembly, and then calls the proper method on that instance. Pertinent lines below hopefully provide context to how I am doing this:
Assembly.LoadFrom(path_to_OtherApp_dll);
...
var x = (dynamic)Activator.CreateInstance(type_inside_OtherApp_dll);
...
var instance = new ConsoleClass();
x.some_method_call(instance);
Ultimately this fails. It seems to be because even though the two projects (ConsoleApp.exe and OtherApp.dll) are referencing the same DLL to define ConsoleClass, the runtime still considers them to be different types.
Any thoughts?
Define the public interface. Put it to its own interface.dll.
Reference interface.dll in your plugin. Let the main class in your plugin.dll implements your interface.
Reference interface.dll in your exe.
Use Assembly.Load() or Assembly.LoadFrom() to load plugin into your exe.
Use CreateInstance() to create instance of your plugin class.
Simply cast created plugin to your interface type.
So you don't need "dynamic" or other complicated things. Just easy, go step by step as I wrote and it will work. Good luck.
Yes, this will happen when ConsoleApp.dll gets loaded twice. Once by the main app, again by a plugin, using its local copy. A type's identity is determined by the assembly it was loaded from.
It isn't that clear to me how that happened. Your first weapon of choice is Fuslogvw.exe, set it up to log all the binds. First thing to do is to doctor the plugin project and set the Copy Local property of the ConsoleApp.dll reference to False so that extra copy isn't there to get accidentally used.
Copying the plugin DLLs to the main app build folder is the never-have-trouble solution, you can load them with Assembly.Load(). Or a subdirectory with a .config file that uses the <probing> element to allow the CLR to find them.
What do you by "runtime is considering them to be of differnt type"? does setup ends with some exception of error? does method in x variable receives something it does not recognize or what?

Namespaces to avoid conflicts - example?

I read that way back programmers have to think of special names for their classes in order to do not conflict with another one when the file got loaded on users PC. That is what I do not understand, if the class was within e.g. DLL, how it could collide with other class on that PC?
Even without namespaces, if I import a DLL, I guess I would need to call the class from that DLL so I could not make the code impossible to complile.
I would really appreciate explanation here, thanks!
example:
System.Drawing.Point and System.Windows.Point
So if a program references both assemblies, without the namespaces, the compiler will get confused when you declare Point p; or Point p = new Point(1,1);, for example
Consider if there are no namespaces. Then you load a type MyClass from an assembly. Now if you load another type from another assembly and there is a MyClass in there. How do you load the second type? How to do tell the compiler which one you want when you say
MyClass o = new MyClass()
The answer - you have to name namespaces to uniquely identify the class, otherwise it's ambiguous. So you say why not limit the name space to the assembly. This is fine, however it appears that is such a great idea that the designers of the platform introduced a concept where anyone can create multiple namespaces within an assembly to allow people to partition their code better. Then we ask why not allow namespaces to go across assemblies so that we can partition the code more easily.
You have many uses for namespaces and it's upto you the app designer to come up with something that works for you - even if its only one namespace.
DLL Hell, the Inside Story is a good summary of the old issues - C# addressed this issuer per design - so you do not need to worry anymore.

If I add a public method to a C# class, do I need to recompile other assemblies using that type?

Question in the title.
I'd like to avoid recompiling since the source code I'm modifying is third party and I'd like to use the original binaries where possible, and replace only the assembly which contains the class I modified. But I'm not sure if this is a safe thing to do. In C++ for example this is definitely a bad idea.
No.
The assemblies that reference your library refer to methods and types using (some form of) name, so as long as you don't change the names of public types and methods (used by other assemblies), you don't need to recompile any of the assemblies - they will work with the updated version of the library.
In most cases Tomas answer is correct, but there are some cases where it is not true:
When using strong naming (signing) change of a single character leads to a new signature, thous leading to a new strong name.
Setting in your project references for your assembly the property Specific Version to true and changing the version number manually or automatically in AssemblyInfo.cs
No. All other assemblies will automatically work with the newly updated library.

Categories