This is more of a tech support question, but the newtonsoft.com website says stackoverflow is the best place to ask questions.
I have a string that was serialized with 6.0.3, and fails to deserialize with 6.0.8. It throws InvalidCastException. When I downgrade to 6.0.3, it deserializes fine; when I upgrade again to 6.0.8, the exception is repeatable.
Edit:
Rather than post the actual string, which is 10KB long and contains sensitive information, I was able to create a simple reproducible test case that demonstrates the problem.
The line that throws exception is:
this.SomeStrings = (string[])infoEnum.Current.Value;
The InvalidCastException says "Unable to cast object of type 'Newtonsoft.Json.Linq.JObject' to type 'System.String[]'"
As mentioned in the comments below, I serialized an instance of FooClass with 6.0.3, and then hard-coded the string into the asdf() method and attempt to deserialize. Deserialization succeeds on 6.0.3, and fails with InvalidCastException on 6.0.8.
Obviously, in the trivial repro case below, there is no point in doing ISerializable on FooClass, but in real life I have a need to use ISerializable in a complex data type that serializes and deserializes itself as a string array; the following is just to academically illustrate reproduction of the bug behavior.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
using System.Runtime.Serialization;
namespace CBClasses
{
[Serializable]
public class FooClass : ISerializable
{
public string[] SomeStrings { get; set; }
public FooClass() { }
protected FooClass(SerializationInfo info, StreamingContext context)
{
if (info == null)
throw new ArgumentNullException();
SerializationInfoEnumerator infoEnum = info.GetEnumerator();
while (infoEnum.MoveNext()) {
SerializationEntry entry = infoEnum.Current;
switch (entry.Name) {
case "SomeStrings":
this.SomeStrings = (string[])infoEnum.Current.Value;
break;
default:
throw new SerializationException("Deserialization failed on unhandled member '" + entry.Name + "'");
}
}
}
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("SomeStrings", this.SomeStrings, this.SomeStrings.GetType());
}
}
public class NewtonsoftDebugTest
{
private static JsonSerializerSettings settings = new JsonSerializerSettings() {
TypeNameHandling = TypeNameHandling.All,
Formatting = Formatting.Indented,
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
ReferenceLoopHandling = ReferenceLoopHandling.Serialize
};
public static void asdf()
{
/* FooClass foo = new FooClass() { SomeStrings = new string[0] };
* string serializedBy603 = JsonConvert.SerializeObject(foo, settings);
* Resulted in:
*
* {
* "$id": "1",
* "$type": "CBClasses.FooClass, CBClasses",
* "SomeStrings": {
* "$type": "System.String[], mscorlib",
* "$values": []
* }
* }
*
* Now hard-coded below:
*/
string serializedBy603 =
"{\n" +
" \"$id\": \"1\",\n" +
" \"$type\": \"CBClasses.FooClass, CBClasses\",\n" +
" \"SomeStrings\": {\n" +
" \"$type\": \"System.String[], mscorlib\",\n" +
" \"$values\": []\n" +
" }\n" +
"}\n";
FooClass deserialized = (FooClass)JsonConvert.DeserializeObject(serializedBy603, settings);
System.Diagnostics.Debugger.Break();
}
}
}
I did some investigation into this and can confirm that the problem first appeared in version 6.0.7 and is still reproducible with the latest release (9.0.1 as of this writing). The change appears to have been made as part of the commit to "Support reference preservation for ISerializable objects" from November 4, 2014. According to the source code diffs, the following code in the CreateISerializable() method of the JsonSerializerInternalReader class was changed from this:
if (reader.TokenType == JsonToken.StartObject)
{
// this will read any potential type names embedded in json
object o = CreateObject(reader, null, null, null, contract, member, null);
serializationInfo.AddValue(memberName, o);
}
else
{
serializationInfo.AddValue(memberName, JToken.ReadFrom(reader));
}
to this:
serializationInfo.AddValue(memberName, JToken.ReadFrom(reader));
It seems pretty clear that the former code used to handle the embedded type metadata, whereas the replacement code does not. And, in fact, I can confirm that reverting this one section of code back to its original state fixes the problem. However, without knowing the intent of this change (maybe the metadata was supposed to be handled somewhere else in the code?), I can't recommend blindly reverting it, as that might break something else. The current serialization code still adds the type metadata as before (I get the same JSON as posted in the question), so this definitely seems to be a regression on the deserialization end. If you haven't already, you might want to report an issue on GitHub. (And yes, I do realize this question is over a year and a half old; I'm just trying to provide some closure here. ;-))
As a workaround, you can extract the string array from the SerializationEntry like this:
this.SomeStrings = ((JObject)entry.Value)["$values"].ToObject<string[]>();
I want to maintain savefile compatibility between multiple versions of my program, but this causes problems with serialization, as the assembly qualified type name changes when I increment the version number, so Type.GetType() can't find it. Is there any way to search for a type disregarding the assembly version?
Whenever a type is not found the AssembyResolvedEvent is fired.
This event can be used to check your types loaded and return that type which has the same name but ignore the version number.
http://msdn.microsoft.com/en-us/library/system.appdomain.assemblyresolve%28v=vs.110%29.aspx
EDIT:
As this was some time ago it seems that I could not recall it all correctly.
Adriano was was correct. The AssemlyResolve ist just asking for the assembly.
So additionally a SerializationBinder is needed. This sounds like work, but is quite simple! I'll try to summarize:
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (args == null || string.IsNullOrEmpty(args.Name))
return null;
//if object was serialized with previous version .dll, deserialze with current version .dll (only relevant with strong names)
foreach (Assembly ass in AppDomain.CurrentDomain.GetAssemblies())
{
if ((args.Name.StartsWith("XYZ.")) // XYZ marks my namespace
&& args.Name.Contains("Culture=neutral") && args.Name.StartsWith(ass.FullName.Split(',')[0]))
return ass;
}
return null;
}
Remark: this checks only for assemblies which are already loaded!
Your SerializationBinder:
public class XYZSerializationBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
Type curType = null;
//if object was serialized with previous version .dll, deserialze with current version .dll (only relevant with strong names)
if (!string.IsNullOrEmpty(assemblyName) && assemblyName.Contains("Culture=neutral")
&& (assemblyName.StartsWith("XYZ.")))
{
string plainAssemblyName = assemblyName.Split(',')[0];
Assembly ass = Assembly.Load(plainAssemblyName);
curType = ass.GetType(typeName);
}
else
{
curType = Type.GetType(string.Format("{0}, {1}", typeName, assemblyName));
}
if (curType == null)
{
return typeof(InvalidType);
}
return curType;
}
}
Now just use the binder!
IFormatter formatter = new BinaryFormatter();
formatter.Binder = serializationBinder;
using (FileStream fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
{
storage = formatter.Deserialize(fileStream);
}
I hope this is what you want / need!
I just figured it out!
I had to use this overload of Type.GetType() to customize the resolution:
http://msdn.microsoft.com/en-us/library/ee332932(v=vs.100).aspx
I did it like so:
type = Type.GetType(typename,
assemblyName =>
{
return AppDomain.CurrentDomain.GetAssemblies().SingleOrDefault(a => a.GetName().Name == assemblyName.Name);
},
(assembly, typeName, caseInsensitive) =>
{
if (caseInsensitive)
return assembly.GetTypes().SingleOrDefault(t => t.FullName.Equals(typeName, StringComparison.InvariantCultureIgnoreCase));
else
return assembly.GetTypes().SingleOrDefault(t => t.FullName == typeName);
});
Note the comparison of GetName().Name, as opposed to FullName, for the assemblies. This is what enables comparison of only the actual names of the assemblies, and not their versions.
I guess that you can use assembly redirection therefore:
http://msdn.microsoft.com/en-us/library/7wd6ex19(v=vs.110).aspx
You should use a SerializationBinder to resolve types.
See: http://msdn.microsoft.com/en-us/library/system.runtime.serialization.serializationbinder%28v=vs.110%29.aspx
Please note that you probably will be better off using XML or DataContract serialization that do not save type information and are also much faster.
As the title says the deserialization fail after protecting my application with themida with the following exception :
Unable to generate a temporary class (result=1).
error CS0009: Metadata file 'c:\Path\to\protected.exe' could not be opened -- 'An attempt was made to load a program with an incorrect format. '
Here's the code I'm using for the deserialization (It works when the exe is not protected):
MyClass myClass;
try
{
using (var stream = new MemoryStream(Data))
{
var serializer = new XmlSerializer(typeof(ComSec.MyClass));
myClass = serializer.Deserialize(stream) as MyClass;
}
}
catch (Exception e)
{
return null;
}
Weird thing is that the code + themida protection works fine on my machine but it fails on the VM and on a co-worker's machine
I'm using (same config as my co-worker) :
VS2012 Professional
Windows 7 x64 Ultimate
Themida 2.1.2.0 x86 (With .Net support)
The VM is a fresh install of Windows 7 x86.
I ended up using the DataContract attribute and using a DataContractSerializer to Serialize and deserialize the object (It works now everywhere and with/without the protection ).
My research:
[DataContract(Name = "TestClass")]
public class TestClass
{
[DataMember(Name = "Name")]
public string Name { get; set; }
[DataMember(Name = "Age")]
public int Age { get; set; }
}
Serialization/Deserialization :
var serializer = new DataContractSerializer(typeof(TestClass));
using (var stream = new MemoryStream())
{
serializer.WriteObject(stream, this);
File.WriteAllBytes("TestClass.xml", stream.ToArray());
}
TestClass o = null;
using (var stream = new MemoryStream(File.ReadAllBytes("TestClass.xml")))
{
o = serializer.ReadObject(stream) as TestClass;
}
I experienced this issue as well and the proposed answer worked fine. The original problem was due to file access permissions. Just adding this information so other people understand why DataContract works (from https://stackoverflow.com/a/10340155/1111380):
DataContractSerializer, NetDataContractSerializer and DataContractJsonSerializer do NOT require disk space and do NOT emit assemblies to disk. Instead, they generate IL on the fly (in memory) and use it during subsequent serialization episodes to do serialization and deserialization all within the AppDomain they're operating in. However, XmlSerializer does require disk space and explains the error (path to the file could not be opened/access).
I'm using the CodeDomProvider to compile some Linq code and execute queries dynamically. However, I'm hitting a very strange issue.
If my Linq query in the generated code looks like this everything works:
namespace Dynamic
{
using System.Linq;
using System.Collections.Generic;
public static class Query
{
public static int GetRecords()
{
MyData.Data.DataMart container = new MyData.Data.DataMart();
return (container.EventDetails).Count();
}
}
}
This compiles and runs just fine. However, if I change the linq query to the following then it fails to compile:
return (from e in container.EventDetails select e).Count();
It works fine if I put this as static code, but if I try to compile it with the CodeDomProvider it fails (and I haven't found any good method to get error messages on why it fails). I would like to use the from-in-select style of syntax since this will make it easier for me to generate the linq queries but I can't figure out why they are not compiling.
You can see some of the code I use to compile this snippet at the link on the top of this post.
Thanks!
Edit: Copying the code from the post I linked to:
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters cp = new CompilerParameters();
cp.GenerateInMemory = true;
cp.ReferencedAssemblies.Add("mscorlib.dll");
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("System.Core.dll");
cp.ReferencedAssemblies.Add("System.Data.Linq.dll");
cp.ReferencedAssemblies.Add("System.Data.Entity.dll");
cp.ReferencedAssemblies.Add("MyApp.Data.dll");
var results = provider.CompileAssemblyFromSource(cp, source);
var assm = results.CompiledAssembly;
Edit2: As far as the exception goes, I get an exception on the second to last line of code (var results = ...). The exception is a BadImageFormatException:
Could not load file or assembly '0 bytes loaded from System,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' or
one of its dependencies. An attempt was made to load a program with an
incorrect format
This seems to work for me:
static void Main(string[] args)
{
string sourceCode = #"namespace Dynamic {
using System.Linq;
using System.Collections.Generic;
public static class Query
{
public static int GetRecords()
{
MyApp.Data.DataMart container = new MyApp.Data.DataMart();
//return (container.EventDetails).Count();
return (from e in container.EventDetails select e).Count();
}
} }";
string sDynamDll = "Dynamic.dll";
string sDynamClass = "Query";
string sDynamMethod = "GetRecords";
System.CodeDom.Compiler.CompilerParameters cp = new CompilerParameters();
cp.GenerateExecutable = false;
cp.GenerateInMemory = true;
cp.OutputAssembly = sDynamDll;
cp.ReferencedAssemblies.Add("mscorlib.dll");
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("System.Core.dll");
cp.ReferencedAssemblies.Add("System.Data.Linq.dll");
cp.ReferencedAssemblies.Add("System.Data.Entity.dll");
cp.ReferencedAssemblies.Add("MyApp.Data.dll");
var providerOptions = new Dictionary<string, string>();
providerOptions.Add("CompilerVersion", "v4.0");
CodeDomProvider compiler = CodeDomProvider.CreateProvider("C#", providerOptions);
CompilerResults cr = compiler.CompileAssemblyFromSource(cp, sourceCode);
if (cr.Errors.HasErrors)
{
StringBuilder errors = new StringBuilder("Compiler Errors :\r\n");
foreach (CompilerError error in cr.Errors)
{
errors.AppendFormat("Line {0},{1}\t: {2}\n", error.Line, error.Column, error.ErrorText);
}
}
// verify assembly
Assembly theDllAssembly = null;
if (cp.GenerateInMemory)
theDllAssembly = cr.CompiledAssembly;
else
theDllAssembly = Assembly.LoadFrom(sDynamDll);
Type theClassType = theDllAssembly.GetType(sDynamClass);
foreach (Type type in theDllAssembly.GetTypes())
{
if (type.IsClass == true)
{
if (type.FullName.EndsWith("." + sDynamClass))
{
theClassType = type;
break;
}
}
}
// invoke the method
if (theClassType != null)
{
object[] method_args = new object[] { };
Object rslt = theClassType.InvokeMember(
sDynamMethod,
BindingFlags.Default | BindingFlags.InvokeMethod,
null,
null, // for static class
method_args);
Console.WriteLine("Results are: " + rslt.ToString());
}
Console.ReadKey();
}
You're probably getting BadImageFormatException because your code isn't actually compiling to a valid assembly. This might be because the old 2.0 compiler is used by default. Check the link below for enabling the C# the 3.5 version (I don't know if 4.0 is supported, but you don't need it):
http://blogs.msdn.com/b/lukeh/archive/2007/07/11/c-3-0-and-codedom.aspx
Also check the Errors collection on the CompilerResult that is returned from the CompileAssemblyFromSource() method. Failure to compile does not throw an exception, you must manually check for compile errors.
I didn't find an answer of how to get good exception information, however, I did solve this problem. The class library that contained the compiler code above was set to AnyCpu but the context it was running in under ASP.Net was x86. So this was causing it to fail when it tried to load System.dll since it was loading the wrong version (or something silly like that).
I'll be happy to give someone else the answer checkmark if you can (a) figure out how to get a real error message from this or (b) load the right reference type.
An application I've been working with is failing when I try to serialize types.
A statement like
XmlSerializer lizer = new XmlSerializer(typeof(MyType));
produces:
System.IO.FileNotFoundException occurred
Message="Could not load file or assembly '[Containing Assembly of MyType].XmlSerializers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified."
Source="mscorlib"
FileName="[Containing Assembly of MyType].XmlSerializers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
FusionLog=""
StackTrace:
at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
I don't define any special serializers for my class.
How can I fix this problem?
Believe it or not, this is normal behaviour. An exception is thrown but handled by the XmlSerializer, so if you just ignore it everything should continue on fine.
I have found this very annoying, and there have been many complaints about this if you search around a bit, but from what I've read Microsoft don't plan on doing anything about it.
You can avoid getting Exception popups all the time while debugging if you switch off first chance exceptions for that specific exception. In Visual Studio, go to Debug -> Exceptions (or press Ctrl + Alt + E), Common Language Runtime Exceptions -> System.IO -> System.IO.FileNotFoundException.
You can find information about another way around it in the blog post C# XmlSerializer FileNotFound exception (which discusses Chris Sells' tool XmlSerializerPreCompiler).
Like Martin Sherburn said, this is normal behavior. The constructor of the XmlSerializer first tries to find an assembly named [YourAssembly].XmlSerializers.dll which should contain the generated class for serialization of your type. Since such a DLL has not been generated yet (they are not by default), a FileNotFoundException is thrown. When that happenes, XmlSerializer's constructor catches that exception, and the DLL is generated automatically at runtime by the XmlSerializer's constructor (this is done by generating C# source files in the %temp% directory of your computer, then compiling them using the C# compiler). Additional constructions of an XmlSerializer for the same type will just use the already generated DLL.
UPDATE: Starting from .NET 4.5, XmlSerializer no longer performs code generation nor does it perform compilation with the C# compiler in order to create a serializer assembly at runtime, unless explicitly forced to by setting a configuration file setting (useLegacySerializerGeneration). This change removes the dependency on csc.exe and improves startup performance. Source: .NET Framework 4.5 Readme, section 1.3.8.1.
The exception is handled by XmlSerializer's constructor. There is no need to do anything yourself, you can just click 'Continue' (F5) to continue executing your program and everything will be fine. If you're bothered by the exceptions stopping the execution of your program and popping up an exception helper, you either have 'Just My Code' turned off, or you have the FileNotFoundException set to break execution when thrown, instead of when 'User-unhandled'.
To enable 'Just My Code', go to Tools >> Options >> Debugging >> General >> Enable Just My Code. To turn off breaking of execution when FileNotFound is thrown, go to Debug >> Exceptions >> Find >> enter 'FileNotFoundException' >> untick the 'Thrown' checkbox from System.IO.FileNotFoundException.
In Visual Studio project properties ("Build" page, if I recall it right) there is an option saying "generate serialization assembly". Try turning it on for a project that generates [Containing Assembly of MyType].
There is a workaround for that. If you use
XmlSerializer lizer = XmlSerializer.FromTypes(new[] { typeof(MyType) })[0];
it should avoid that exception. This worked for me.
WARNING: Do not use multiple times, or you will have a memory leak
You will leak memory like crazy if you use this method to create instances of XmlSerializer for the same type more than once!
This is because this method bypasses the built-in caching provided the XmlSerializer(type) and XmlSerializer(type, defaultNameSpace) constructors (all other constructors also bypass the cache).
If you use any method to create an XmlSerializer that is not via these two constructors, you must implement your own caching or you'll hemorrhage memory.
I ran into this exact issue and couldn't get around it by any of the solutions mentioned.
Then I finally found a solution.
It appears that the serializer needs not only the type, but the nested types as well.
Changing this:
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
To this:
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T).GetNestedTypes());
Fixed the issue for me.
No more exceptions or anything.
My solution is to go straight to reflection to create the serializer. This bypasses the strange file loading that causes the exception. I packaged this in a helper function that also takes care of caching the serializer.
private static readonly Dictionary<Type,XmlSerializer> _xmlSerializerCache = new Dictionary<Type, XmlSerializer>();
public static XmlSerializer CreateDefaultXmlSerializer(Type type)
{
XmlSerializer serializer;
if (_xmlSerializerCache.TryGetValue(type, out serializer))
{
return serializer;
}
else
{
var importer = new XmlReflectionImporter();
var mapping = importer.ImportTypeMapping(type, null, null);
serializer = new XmlSerializer(mapping);
return _xmlSerializerCache[type] = serializer;
}
}
To avoid the exception you need to do two things:
Add an attribute to the serialized class (I hope you have access)
Generate the serialization file with sgen.exe
Add the System.Xml.Serialization.XmlSerializerAssembly attribute to your class.
Replace 'MyAssembly' with the name of the assembly where MyClass is in.
[Serializable]
[XmlSerializerAssembly("MyAssembly.XmlSerializers")]
public class MyClass
{
…
}
Generate the serialization file using the sgen.exe utility and deploy it with the class’s assembly.
‘sgen.exe MyAssembly.dll’ will generate the file MyAssembly.XmlSerializers.dll
These two changes will cause the .net to directly find the assembly.
I checked it and it works on .NET framework 3.5 with Visual Studio 2008
Function XmlSerializer.FromTypes does not throw the exception, but it leaks the memory. Thats why you need to cache such serializer for every type to avoid memory leaking for every instance created.
Create your own XmlSerializer factory and use it simply:
XmlSerializer serializer = XmlSerializerFactoryNoThrow.Create(typeof(MyType));
The factory looks likes:
public static class XmlSerializerFactoryNoThrow
{
public static Dictionary<Type, XmlSerializer> _cache = new Dictionary<Type, XmlSerializer>();
private static object SyncRootCache = new object();
/// <summary>
/// //the constructor XmlSerializer.FromTypes does not throw exception, but it is said that it causes memory leaks
/// http://stackoverflow.com/questions/1127431/xmlserializer-giving-filenotfoundexception-at-constructor
/// That is why I use dictionary to cache the serializers my self.
/// </summary>
public static XmlSerializer Create(Type type)
{
XmlSerializer serializer;
lock (SyncRootCache)
{
if (_cache.TryGetValue(type, out serializer))
return serializer;
}
lock (type) //multiple variable of type of one type is same instance
{
//constructor XmlSerializer.FromTypes does not throw the first chance exception
serializer = XmlSerializer.FromTypes(new[] { type })[0];
//serializer = XmlSerializerFactoryNoThrow.Create(type);
}
lock (SyncRootCache)
{
_cache[type] = serializer;
}
return serializer;
}
}
More complicated version without possibility of memory leak (please someone review the code):
public static XmlSerializer Create(Type type)
{
XmlSerializer serializer;
lock (SyncRootCache)
{
if (_cache.TryGetValue(type, out serializer))
return serializer;
}
lock (type) //multiple variable of type of one type is same instance
{
lock (SyncRootCache)
{
if (_cache.TryGetValue(type, out serializer))
return serializer;
}
serializer = XmlSerializer.FromTypes(new[] { type })[0];
lock (SyncRootCache)
{
_cache[type] = serializer;
}
}
return serializer;
}
}
This exception can also be trapped by a managed debugging assistant (MDA) called BindingFailure.
This MDA is useful if your application is designed to ship with pre-build serialization assemblies. We do this to increase performance for our application. It allows us to make sure that the pre-built serialization assemblies are being properly built by our build process, and loaded by the application without being re-built on the fly.
It's really not useful except in this scenario, because as other posters have said, when a binding error is trapped by the Serializer constructor, the serialization assembly is re-built at runtime. So you can usually turn it off.
Troubleshooting compilation errors on the other hand is very complicated. These problems manifest themselves in a FileNotFoundException with the message:
File or assembly name abcdef.dll, or one of its dependencies, was not found. File name: "abcdef.dll"
at System.Reflection.Assembly.nLoad( ... )
at System.Reflection.Assembly.InternalLoad( ... )
at System.Reflection.Assembly.Load(...)
at System.CodeDom.Compiler.CompilerResults.get_CompiledAssembly()
You may wonder what a file not found exception has to do with instantiating a serializer object, but remember: the constructor writes C# files and tries to compile them. The call stack of this exception provides some good information to support that suspicion. The exception occurred while the XmlSerializer attempted to load an assembly generated by CodeDOM calling the System.Reflection.Assembly.Load method. The exception does not provide an explanation as to why the assembly that the XmlSerializer was supposed to create was not present. In general, the assembly is not present because the compilation failed, which may happen because, under rare circumstances, the serialization attributes produce code that the C# compiler fails to compile.
Note
This error also occurs when the XmlSerializer runs under an account or a security environment that is not able to access the temp directory.
Source:
http://msdn.microsoft.com/en-us/library/aa302290.aspx
In Visual Studio project properties there is an option saying "generate serialization assembly". Try turning it on for a project that generates [Containing Assembly of MyType].
Just as reference. Taking from D-B answer and comments, I came with this solution which is close to D-B solution. It works fine in all of my cases and it is thread safe. I don't think that using a ConcurrentDictionary would have been ok.
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
namespace HQ.Util.General
{
public class XmlSerializerHelper
{
private static readonly Dictionary<Type, XmlSerializer> _dictTypeToSerializer = new Dictionary<Type, XmlSerializer>();
public static XmlSerializer GetSerializer(Type type)
{
lock (_dictTypeToSerializer)
{
XmlSerializer serializer;
if (! _dictTypeToSerializer.TryGetValue(type, out serializer))
{
var importer = new XmlReflectionImporter();
var mapping = importer.ImportTypeMapping(type, null, null);
serializer = new XmlSerializer(mapping);
return _dictTypeToSerializer[type] = serializer;
}
return serializer;
}
}
}
}
Usage:
if (File.Exists(Path))
{
using (XmlTextReader reader = new XmlTextReader(Path))
{
// XmlSerializer x = new XmlSerializer(typeof(T));
var x = XmlSerializerHelper.GetSerializer(typeof(T));
try
{
options = (OptionsBase<T>)x.Deserialize(reader);
}
catch (Exception ex)
{
Log.Instance.AddEntry(LogType.LogException, "Unable to open Options file: " + Path, ex);
}
}
}
A custom class to serialise:
[Serializable]
public class TestClass
{
int x = 2;
int y = 4;
public TestClass(){}
public TestClass(int x, int y)
{
this.x = x;
this.y = y;
}
public int TestFunction()
{
return x + y;
}
}
I have attached the code snippet. Maybe this can help you out.
static void Main(string[] args)
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(TestClass));
MemoryStream memoryStream = new MemoryStream();
XmlTextWriter xmlWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
TestClass domain = new TestClass(10, 3);
xmlSerializer.Serialize(xmlWriter, domain);
memoryStream = (MemoryStream)xmlWriter.BaseStream;
string xmlSerializedString = ConvertByteArray2Str(memoryStream.ToArray());
TestClass xmlDomain = (TestClass)DeserializeObject(xmlSerializedString);
Console.WriteLine(xmlDomain.TestFunction().ToString());
Console.ReadLine();
}
I was having a similar problem, and ignoring the exception did not work for me. My code was calling NServiceBus' configuration Configure.With(...).XmlSerializer()...
What fixed it for me was to change the platform for my project.
Go to Build\Configuration Manager...
Find your project and change Platform (in my case from x86 to Any CPU)
Seen a lot of recommendations to use a ConcurrentDictionary, but no solid examples of it, so I'm going to throw my hat into this solution race. I'm not a thread-safe developer, so if this code isn't solid, please speak up for the sake of those who follow after.
public static class XmlSerializerHelper
{
private static readonly ConcurrentDictionary<Type, XmlSerializer> TypeSerializers = new ConcurrentDictionary<Type, XmlSerializer>();
public static XmlSerializer GetSerializer(Type type)
{
return TypeSerializers.GetOrAdd(type,
t =>
{
var importer = new XmlReflectionImporter();
var mapping = importer.ImportTypeMapping(t, null, null);
return new XmlSerializer(mapping);
});
}
}
I've seen other posts involving ConcurrentDictionary and Lazy loading the value. I'm not sure if that's relevant here or not, but here's the code for that:
private static readonly ConcurrentDictionary<Type, Lazy<XmlSerializer>> TypeSerializers = new ConcurrentDictionary<Type, Lazy<XmlSerializer>>();
public static XmlSerializer GetSerializer(Type type)
{
return TypeSerializers.GetOrAdd(type,
t =>
{
var importer = new XmlReflectionImporter();
var mapping = importer.ImportTypeMapping(t, null, null);
var lazyResult = new Lazy<XmlSerializer>(() => new XmlSerializer(mapping), LazyThreadSafetyMode.ExecutionAndPublication);
return lazyResult;
}).Value;
}
Your type may reference other assemblies which cannot be found neither in the GAC nor in your local bin folder ==> ...
"or one of its dependencies. The system
cannot find the file specified"
Can you give an example of the type you want to serialize?
Note: Ensure that your type implements Serializable.
I was getting the same error, and it was due to the type I was trying to deserialize not having a default parameterless constructor. I added a constructor, and it started working.
I had the same problem until I used a 3rd Party tool to generate the Class from the XSD and it worked! I discovered that the tool was adding some extra code at the top of my class. When I added this same code to the top of my original class it worked. Here's what I added...
#pragma warning disable
namespace MyNamespace
{
using System;
using System.Diagnostics;
using System.Xml.Serialization;
using System.Collections;
using System.Xml.Schema;
using System.ComponentModel;
using System.Xml;
using System.Collections.Generic;
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.6.1064.2")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class MyClassName
{
...
Had a similar problem in one of my .Net Standard dlls.
I used Microsoft.XmlSerializer.Generator nuget, which pre-generating XmlSerializer on .Net Core and .Net Standard.
Initial answer from Martin Sheburn is correct.
Code samples from edeboursetty, tomas-kubes), quadfinity should solve the problem of not raising excess exceptions in debugger.
Here is a shorter solution, however:
internal sealed static class XmlSerializerHelper
{
private static readonly ConcurrentDictionary<Type, System.Xml.Serialization.XmlSerializer> s_xmlSerializers = new();
public static System.Xml.Serialization.XmlSerializer Get<T>()
{
return s_xmlSerializers.GetOrAdd(typeof(T), _ => System.Xml.Serialization.XmlSerializer.FromTypes(new [] {typeof(T)})[0]);
}
}