I have a solution "First" which consists of few projects. One of the projects references the other projects's dlls. I add them via browsing to a specific location.
When I start another solution "Second" with one simple windows app, I add reference to "First" and to two of "First"'s projects, which extend one from another. I add the references via code from "First".
Now, in "First", I have this line of code:
OneProject hello = OneProjectList[OneProjectList.Count - 1];
StringWriter sw = new StringWriter();
XmlSerializer serializer=new XmlSerializer(hello.GetType(),new Type[]{typeof(OneProject)});
serializer.Serialize(sw, hello);
The project crashes on the last line. The exception says {"[A]Something.X cannot be cast to [B]Something.X.
Type A originates from 'Something, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'LoadFrom' at location 'goodLocation'.
Type B originates from 'EL_CL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'LoadNeither' at location
'C:\Users\John\AppData\Local\Microsoft\VisualStudio\8.0\ProjectAssemblies\p3www12k01\EL_CL.dll'."}
In the Output window in VS, I have: 'devenv.exe' (Managed): Loaded 'C:\Users\John\AppData\Local\Microsoft\VisualStudio\8.0\ProjectAssemblies\p3www12k01\Something.dll', No symbols loaded.
Why is this assembly getting loaded? That line in the Output window is shown while serializer.Serialize(sw, hello);, and right after that the program crashes.
Note that Something = hello.GetType().
Does it work if you take out the extra Type array from your XmlSerializer constructor?
XmlSerializer serializer = new XmlSerializer(hello.GetType);
Related
I discovered that after my application generates Telerik report
var result = new ReportProcessor().RenderReport("PDF", new InstanceReportSource { ReportDocument = new MyTelerikReport(data) }, null);
var stream = new MemoryStream(result.DocumentBytes);
return CreateHttpFileResponse("MyReport.pdf", stream, "application/pdf");
I am not able to get all types within CurrentDomain
var typesWithAttribute = (from a in AppDomain.CurrentDomain.GetAssemblies()
from t in a.GetTypes() //error appears here
//some filtering logic
select t).ToList();
I am getting error
System.Reflection.ReflectionTypeLoadException: Unable to load one or
more of the requested types. Retrieve the LoaderExceptions property
for more information.
LoaderExceptions:
System.IO.FileNotFoundException: Could not load file or assembly
'DocumentFormat.OpenXml, Version=2.0.5022.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The
system cannot find the file specified. File name:
'DocumentFormat.OpenXml, Version=2.0.5022.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35'
After some investigation I found that assembly that fails to load: Telerik.Reporting.OpenXmlRendering, Version=8.0.14.311, Culture=neutral, PublicKeyToken=a9d7983dfcc261be and that assembly doesn't exists in AppDomain.CurrentDomain.GetAssemblies() before I generate report (I assume that assembly loaded dynamically by Telerik.Reporting, Version=8.0.14.311, Culture=neutral, PublicKeyToken=a9d7983dfcc261be).
I could filter out that assembly as I don't need any types from that but I am a bit worried about fact of having assemblies in domain that cannot be loaded - seems a bit wrong to me.
Could someone explain what there happens? Is it my issue or that is fault of 3rd party library that doesn't load all required assemblies?
The issue is not the assembly but the Type coming from a dependent assembly that has not been loaded.
If the GetTypes method is called on an assembly and a type in that assembly is dependent on a type in an assembly that has not been loaded (for example, if it derives from a type in the second assembly), a ReflectionTypeLoadException is thrown.
http://msdn.microsoft.com/en-us/library/system.reflection.assembly.gettypes(v=vs.110).aspx
In Suzanne Cook's .NET CLR Notes she talks about the dangers of the "LoadFrom" context. Specifically,
If a Load context assembly tries to load this assembly by display name, it will fail to be found by default (e.g., when mscorlib.dll deserializes this assembly)
Worse, an assembly with the same identity but at a different path could be found on the probing path, causing an InvalidCastException, MissingMethodException, or unexpected method behavior later on.
How do you reproduce this behavior with deserialization, but without explicitly loading two different versions of the assembly?
I've created a Console application, A.exe, which indirectly loads (via `Assembly.LoadFrom) and calls (via reflection) code from a class library, B.dll.
A.exe does not (necessarily) have a reference to B.dll, but B.dll should exist in the same directory as A.exe
A copy of of B.dll should be placed into another directory (here I've used the subdirectory called LoadFrom), this is the location we will use Assembly.LoadFrom on.
A.exe
class Program
{
static void Main(string[] args)
{
// I have a post build step that copies the B.dll to this sub directory.
// but the B.dll also lives in the main directory alongside the exe:
// mkdir LoadFrom
// copy B.dll LoadFrom
//
var loadFromAssembly = Assembly.LoadFrom(#".\LoadFrom\B.dll");
var mySerializableType = loadFromAssembly.GetType("B.MySerializable");
object mySerializableObject = Activator.CreateInstance(mySerializableType);
var copyMeBySerializationMethodInfo = mySerializableType.GetMethod("CopyMeBySerialization");
try
{
copyMeBySerializationMethodInfo.Invoke(mySerializableObject, null);
}
catch (TargetInvocationException tie)
{
Console.WriteLine(tie.InnerException.ToString());
}
Console.ReadKey();
}
}
B.dll
namespace B
{
[Serializable]
public class MySerializable
{
public MySerializable CopyMeBySerialization()
{
return DeepClone(this);
}
private static T DeepClone<T>(T obj)
{
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
ms.Position = 0;
return (T)formatter.Deserialize(ms);
}
}
}
}
Output
System.InvalidCastException:
[A]B.MySerializable cannot be cast to
[B]B.MySerializable.
Type A originates from 'B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
in the context 'Default' at location 'c:\Dev\bin\Debug\B.dll'.
Type B originates from 'B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
in the context 'LoadFrom' at location 'c:\Dev\bin\Debug\LoadFrom\B.dll'.
at B.MySerializable.DeepClone[T](T obj)
at B.MySerializable.CopyMeBySerialization()
Here's what is happening:
When the call to formatter.Deserialize(ms) is made, it uses the information stored in the MemoryStream to determine what type of object it needs to create (and which assembly it needs in order to create that object).
It finds that it needs B.dll and attempts to Load it (from the default "Load" context).
The currently loaded B.dll is not found (because it was loaded in the "LoadFrom" context).
Thus, an attempt is made to find B.dll in the usual locations--it is found in the ApplicationBase directory and is loaded.
All types in this B.dll are considered different types that those from the other B.dll. Thus the cast in the expression (T)formatter.Deserialize(ms) fails.
Additional notes:
If the B.dll had not existed somewhere where A.exe could find it using Assembly.Load, then instead of an InvalidCastException, there would be a SerializationException with the message Unable to find assembly 'B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
The same problem occurs even with signed assemblies, but what is more alarming with signed assemblies is that it can load a different version of the signed assembly. That is, if B.dll in the "LoadFrom" context is 1.0.0.0, but the B.dll found in the main directory is 2.0.0.0, the serialization code will still load the wrong version B.dll to do deserialization.
The DeepClone code I've shown seems to be one of the more popular ways to do a deep clone on an object. See: Deep cloning objects in C#.
So, from any code that was loaded into the "LoadFrom" context, you cannot use deserialization successfully (without jumping through additional hoops to allow the assembly to successfully load in the default "Load" context).
I want to develop an application like Visual studio Object Browser, i.e. user will enter something like System.Text namespace or system classes. After button click, we have to find out all classes, functions, properties etc. inside the "System.Text".
I tried the following, but that failed.
Assembly SampleAssembly;
SampleAssembly = Assembly.Load("System.Text");
Type[] Types = SampleAssembly.GetTypes();
// Display all the types contained in the specified assembly.
StringBuilder str = new StringBuilder();
foreach (Type oType in Types)
{
str.Append(oType.Name.ToString() + "</br>");
}
divAsseblyData.InnerHtml = str.ToString();
'System.Text' is a namespace not an assembly so i assume you want to load the assembly 'System'.
To use Assembly.Load() with a string parameter you need to pass the fully qualified name of the assembly.
To obtain the fully qualified name you can do something like this:
Assembly SampleAssembly;
SampleAssembly = Assembly.Load(typeof(System.Activator).Assembly.FullName);
// get the type of some random object in the assembly (Activator) and then
// call .Assembly.FullName which returns the fully qualified name of the assembly
Or you can press Win + R, type "Assembly" and enter, then right click -> proprieties on the assembly which you need and set manually the proprieties in code in the format:
"mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
SampleAssembly = Assembly.Load("mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
I have a very strange problem here. It looks like unless I instantiate a class within an assembly I get an assembly not found error.
For example:
Assembly.Load("something.blah, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
Type mqType = Type.GetType(query.Attribute(fullyQualifiedName + ", " + assemblyInfo);
Object mq = Activator.CreateInstance(mqType);
Throws a FileNotFound exception on Assembly.Load
This:
Assembly.Load("something.blah, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
new someClassInAssembly();
Type mqType = Type.GetType(query.Attribute(fullyQualifiedName + ", " + assemblyInfo);
Object mq = Activator.CreateInstance(mqType);
Works fine. Yes, even if it is instantiated after Assembly.Load, so it is clearly a problem during compilation. How do I explicitly make sure that the assembly is loaded and findable during runtime, is there a compilation setting somewhere, what do I need to do?
Make sure you're loading the assembly you think you're loading, by supplying the path:
AssemblyName an = AssemblyName.GetAssemblyName(filePath);
Assembly.Load(an);
Honestly, if its just a single reference or a handful, just add an explicit reference somewhere it will save you a lot of effort.
//Use a static constructor somewhere appropriate.
static someClass(){
new AssemblyYouCareAbout.Object();
}
The alternatives are along the lines of hauling dlls manually to the bin of your running process or to add the dlls to the gac. I'd rather use the not-so-elegant static constructor and move on.
I have this weird problem that I cannot handle myself. A class in the model of my mvp-project designed as singleton causes an InvalidCastException.
The source of error is found in this code line where the deserialised object is assigned to the instance variable of the class: engineObject = (ENGINE)xSerializer.Deserialize(str);. It occurs whenever I try to add one of my UserControls to a Form or to a different UC. All of my UCs have a special presenter that accesses the above mentioned instance variable of the singleton class.
This is what I get when trying to add a UC somewhere:
'System.TypeInitializationException: The type initializer for 'MVP.Model.EngineData' threw an exception. ---->
System.InvalidCastException: [A]Engine cannot be cast to [B]Engine. Type A originates from 'MVP.Model, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'LoadNeither'
at location '[...]\AppData\Roaming\Microsoft\VisualStudio\9.0\ProjectAssemblies\uankw1hh01\MVP.Model.dll'.
Type B originates from 'MVP.Model, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'LoadNeither'
at location '[...]\AppData\Roaming\Microsoft\VisualStudio\9.0\ProjectAssemblies\u_hge2de01\MVP.Model.dll'
...
So I somehow have two assemblies and they are not accessed from my project folder, but from a VS temp folder? I googled a lot and only found this: IronPython Exception: [A]Person cannot be cast to [B]Person. There is a solution offered, but it concerns IronPhyton and I don't know where to use it within my project.
Types are per-assembly; if you have "the same" assembly loaded twice, then types in each "copy" of the assembly are not considered to be the same type.
These issues normally crop up when the two assemblies are in the Load and LoadFrom contexts. See
Difference between LoadFile and LoadFrom with .NET Assemblies?
and the link to suzcook's blog for details on that issue.
Also, consider using the fusion log viewer to help diagnose the problem.
http://msdn.microsoft.com/en-us/library/e74a18c4%28VS.71%29.aspx
Judging by the context in which the assembly is getting loaded (the context is "LoadNeither"), some developers may be doing something like loading an assembly that has been internally packaged as a resource with your application. If you do this, you will be using the AppDomain.CurrentDomain.AssemblyResolve event handler, so that your application can specify where .NET should get any particular assembly that it needs.
My answer will not explain the machinations of how to do that - but I'm mentioning it because this process led directly to the same exact error encountered by the original poster. As Eric Lippert mentions, types are per-assembly. So if you load an individual assembly more than once, the same defined class will appear as different classes - even though visual inspection shows that they appear to be the same.
We've seen instances in which .NET will call the ResolveEventHandler more than once for the same DLL. I'm not sure why .NET sometimes does this (it happened on some machines, but not all machines). But to resolve the problem, we needed keep a global list of handles to loaded assemblies, so that if .NET wanted to load the assembly again, we returned a handle to the same Assembly that was originally loaded, instead of loading another copy into memory.
I have included the code that caused the issue for us, and notes about how to handle it properly.
public void AppStartup (object sender, StartupEventArgs e)
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
public System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string dllName = args.Name.Contains(',') ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll", "");
dllName = dllName.Replace(".", "_");
if (dllName.EndsWith("_resources")) return null;
System.Resources.ResourceManager rm = new System.Resources.ResourceManager(GetType().Namespace + ".Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly());
byte[] bytes = null;
try
{
bytes = (byte[])rm.GetObject(dllName);
}
catch (Exception ex)
{
}
if (bytes != null)
{
// the following call will return a newly loaded assembly
// every time it is called
// if this function is called more than once for the same
// assembly, you'll load more than one copy into memory
// this can cause the InvalidCastException
// instead of doing this, you keep a global list of loaded
// assemblies, and return the previously loaded assembly
// handle, instead of loading it again
return System.Reflection.Assembly.Load(bytes);
}
return null;
}
My situation involved two copies of the same dll. One was in the bin folder and one was in a sub-folder of the same bin folder. Both were loaded, amazingly some things worked fine, but some things didn't and that's when this error message appeared:
System.InvalidOperationException; There was an error generating the XML document.; Source: System.Xml; TargetSite: Void Serialize(System.Xml.XmlWriter, System.Object, System.Xml.Serialization.XmlSerializerNamespaces, System.String, System.String);
Hidden in this was the following inner exception (this was to do with Microsoft Dynamics CRM 4.0, but could relate to anything)
System.InvalidCastException; [A]XXX.CRMCustomCode.YYY.CreateCompanyRequest cannot be cast to [B]XXX.CRMCustomCode.YYY.CreateCompanyRequest. Type A originates from 'XXX.CRMCustomCode, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'LoadFrom' at location 'C:\Program Files\Microsoft CRM\Server\bin\assembly\XXX.CRMCustomCode.dll'. Type B originates from 'XXX.CRMCustomCode, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'Default' at location 'C:\Program Files\Microsoft CRM\Server\bin\XXX.CRMCustomCode.dll'.;
I simply deleted the duplicate dll (in C:\Program Files\Microsoft CRM\Server\bin) and the error went away.
My particular case - class library referenced in web application was renamed and rebuilt. Older version of library was still in bin folder under old name. The framework loads whatever in bin folder (both libraries) and emits this error. So it happens not only when assemblies are loaded explicitly.
The obvious solution in my case is to clean bin folder.
I got it working when I tried changing this cast:
var t = (TeacherWebPages)Session["TeachersAD"];
To this:
var t = Session["TeachersAD"] as TeacherWebPages;
However the assembly/session/memcache was different and no data got back but no error occurred. So later I still had to delete specific temporary files every time source page was changed from the folder it was complaining about which would require me to kill IIS process from task manager. Or in my case I can just logout and it clears the session state.