Cast Exception between objects loaded from the same assembly in different locations - c#

I'm trying to use a supplied DLL that load the same dependent DLL from two different locations.
In the supplier deployment the two locations conicide, but not in mine.
When code runs I have a class cast exception:
Unable to cast [A]Type to [B]Type
The error is the same occurred to the op in StackOverflow question Different location of assemblies stoped the type casting.
The two types are the same type loaded from the two different locations of the DLL (the same physical file copied in two directories).
I've tried to use Strong Name with signature of the double DLL, but it did not work.
Is there a way I can tell CLR to treat the two types as the same type?

I'm pretty sure this isn't allowed for a lot of reasons.
First off, let's say you have 2 assemblies. The first defines Animal and has a descendant called Dog. The second defines Animal. Both assemblies use the same namespace.
During runtime what happens when you declare var B = new Dog();? Should the code swap the second assembly's version of Animal in there or not?
What if you declare var A = new Animal();? IMHO, the code should simply implode to prevent it.
From a security perspective you would absolutely not want someone to simply link in another assembly that defines the same namespace as your library to swap out a particular class.
Point is, by linking to both physical assemblies containing the exact same types you are introducing a huge problem that there is no real way to solve. Change your code to work the same way as the supplier.

Related

Use assembly from a library which has been created through ILMerge

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.

Hiding types from being listed in Assembly.GetTypes in .net

Ive been looking everywhere for a possible solution to this but can't seem to find an answer. My issue is that I have a few classes that need to completely hidden from Assembly.getTypes, as I'm writing a plugin for an application, and it's picking up types that I need to remain hidden (this happens even if they are declared as private or internal classes).
anyone know how to either alter what assembly.GetTyes returns, or an ,aficionado attribute that will keep those types from being listed?
This is quite a hack and is very fragile, but could work.
Create 2 assemblies -- one for the plug-in and the second for the other types. The second would be placed in another known directory and loaded dynamically into the first when needed. (For example, via Assembly.LoadFrom.)
The first assembly would then be placed in the plug-in directory and only ever publish its types. This very fragile because you would likely have to hard-code a path to the second assembly and you run the risk of the file getting deleted or moved.
EDIT
#SLaks' comment takes away the fragility of this solution. If you embed the second assembly as a resource and load it at run-time, the app calling Assembly.GetTypes won't see the types you want hidden.
This is not possible.
Sorry.
Code that calls Assembly.GetTypes() should typically filter for only public types.
Welcome to managed code. Complete type information is necessary to .NET's type verifier. Only native code can be hidden from .NET metadata, and then you give up the portability and permissions supported by pure MSIL.

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.

Unable to cast transparent proxy to type from AppDomain

I'm trying to create an object in an appdomain:
var type = typeof (CompiledTemplate);
var obj = (CompiledTemplate) domain.CreateInstanceAndUnwrap (
type.Assembly.FullName, type.FullName);
However, I always get the following error:
Unable to cast transparent proxy to type 'Mono.TextTemplating.CompiledTemplate'.
I'm running on .NET 4.0, not Mono, despite what the namespace might suggest :)
As far as I know, this error happens when .NET thinks that the Type & Assembly do not exactly match in the two domains. However, when debugging, the FullName and Location are identical. Only the Assembly.Codebase property differs - in the child AppDomain its extension is uppercased to "DLL" for some reason.
I've tried adding an AssemblyResolve handler to the AppDomain, which uses Assembly.LoadFrom to load the filename explicitly, but the CodeBase's extension still gets uppercased. Since the original assembly was also loaded with Assembly.LoadFrom (via Mono.Addins), the difference between the CodeBase values seems very strange.
Any suggestions for fixing or working around this problem?
Could you be running into an issue with assembly load contexts?
(e.g. see here)
You have a type that's clearly in the load context (because you're using typeof(CompiledTemplate)), but you're saying that the type in the secondary AD is loaded into the load-from context...
Did you check with fuslogvw to determine exactly what assemblies are being loaded? The fuslog trace will also tell you if the assemblies are being loaded into different contexts.
Perhaps you can use the dynamic keyword instead of casting it to a specific type:
var type = typeof (CompiledTemplate);
dynamic obj = domain.CreateInstanceAndUnwrap (
type.Assembly.FullName, type.FullName);
That might at least give you a workaround to the problem. Of course, the potential drawbacks will be not having compile time checking and/or slower performance. However, these might be negligible trade-offs depending on your situation.
A second copy of the assembly is, indeed, being loaded into memory as it is.
An instance of a type in the runtime is specific to the instance of the assembly loaded - so even if the same DLL file is loaded in a second time, the types are not considered to match.
This is a typical problem when "DLLHell" is extended into the "GACAndDLLHell". "GACONLYHeaven" is a better place ... :).
That the filenames are subtly different (the .DLL extension has a different case) implies that the same DLL is being loaded from two places (that is: the GAC is case-insensitive/always lower case on filenames IIRC).
An abstract class or, preferably, an interface is what you need here.
If you can't make changes to the code base I would, first, make very sure that the DLL exists in only 1 place on the drive (or 0 places on the drive if it is being loaded from the GAC). A copy of the DLL that contains the type: 'CompiledTemplate' in your app /bin folder would be a real culprit ...?
Is this new code or existing code that is now failing for some reason?
I have a WCF net named pipes application that uses a callback (duplex) architecture.
I got this error because my service interface's [ServiceContract] was annotated with the wrong callback.

Categories