Serialization issue on custom type - c#

I have following classes:
[Serializable]
public class TradeBotSettings
{
public ExchangePlatform Exchange
{
get;
set;
}
}
[Serializable]
public enum ExchangePlatform
{
[XmlEnum("BTC_E")]
BTC_E,
[XmlEnum("BitStamp")]
BitStamp,
[XmlEnum("CampBX")]
CampBX,
[XmlEnum("Cryptsy")]
Cryptsy,
[XmlEnum("BTCChina")]
BTCChina,
}
When i try to serialize gives error
private void Button2_Click(object sender, EventArgs e)
{
TradeBotSettings tbSettings = new TradeBotSettings();
tbSettings.Exchange = ExchangePlatform.BTC_E;
StreamWriter sw = new StreamWriter(#"D:\Temp\Trader\Trader\Trader\bin\x86\Debug\configs\bots.xml", false);
xmlSerializerTradebot = new XmlSerializer(tbSettings.GetType());
xmlSerializerSettings.Serialize(sw, tbSettings);
sw.Close();
}
Error is : An unhandled exception of type 'System.InvalidOperationException' occurred in System.Xml.dll
Additional information: There was an error generating the XML document.
This looks like a generic error anyone have a clue about this
Thanks in advance

The code you presented wont compile, xmlSerializerSettings is unknown. This probably should have been "xmlSerializerTradebot.Serialize(..." instead, and this works fine. Maybe that´s your problem?
BTW: You should use the "using" clause when creating StreamWriter instances to prevent having the file not immediately closed in case of serialization exceptions. You also dont need to use the XMLEnum attribute unless you want to have the default serialization behaviour for enums changed...
BTW2: Yeah, i know, this is not a clear answer to the problem and i should rather comment. I would if i already could... ;-)

Related

ASP.NET cannot parse xml! Check file path

I created a simple API via ASP.NET MVC 4:
public class ActionController : ApiController
{
[WebMethod]
public string getCommunities()
{
try
{
MethodClass method = new MethodClass();
return method.getCommunities();
}
catch(Exception ex)
{
return ex.Message.ToString();
}
}
}
which is trying to call this method in the Method class:
public string getCommunities()
{
return "bbb";
}
but for whatever reason, I get this error:
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">cannot parse xml! Check file path</string>
I tried Googling for the error, but came up with nothing, has anyone seen this error before? and how do I fix it?
As already pointed in comments, you are looking for your bug in the wrong place. method.getCommunities() is throwing an error with message "cannot parse xml! Check file path".
Googling your error it seems to me that you are throwing a custom exception: searching for that string in your code may point you to the right place.
As a quick proof of concept I changed the standard API generated by Visual Studio Web API template.
public string Get(int id)
{
try
{
var t = 0;
var i = 1 / t;
return "bbb";
}
catch { return "ABBA"; }
}
which exactly returns the custom error message as xml string
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">ABBA</string>
I attempted to replicate the case you mention by creating simple ActionController.cs in ASP.Net MVC 4 template as follow:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Services;
namespace MvcApiApplicationTrial1.Controllers
{
public class ActionController : ApiController
{
[WebMethod]
public string getCommunities() {
try {
MethodClass method = new MethodClass();
return method.getCommunities();
} catch (Exception ex) {
return ex.Message.ToString();
}
}
}
public class MethodClass
{
public string getCommunities() {
return "bbb";
}
}
}
And call it in the web browser (Chrome) with the following url:
http://localhost:56491/api/Action/getCommunities
And get the following correct result:
If you declare, define, and call things right, your code should have no problem at all.
So, I suggest you to re-check your declaration, definition, as well as your calling to the related Controller/Method again. Your problem may lay somewhere else.
And since the error seems to be a custom error, judging from the code posted alone, likely that the problem lays somewhere in your getCommunities method. Check the method, try to find the "cannot parse xml!" text there. Alternatively, but less likely, the error is in the MethodClass constructor. Same thing, check your MethodClass, try to find the "cannot parse xml!" text.
As for the given case as what you have posted in your question, I found no issue at all.
But anything else in between try and "bbb" can also potentially be the source of the created error. Checking the error text would be my first step if there are more things in the try block and I am unsure where the error may actually be generated.
in Global.asax.cs should put code bellow:
GlobalConfiguration.Configuration.Formatters.Clear();
GlobalConfiguration.Configuration.Formatters.Add(new System.Net.Http.Formatting.XmlMediaTypeFormatter());
and in WebApiConfig code bellow:
config.Formatters.XmlFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml"));
var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");

Load xaml viewmodel at run-time with windows phone

I'm currently following a windows phone tutorial from Microsoft virtual academy and one of the challenges was to use the design xaml viewmodel that was created in the project and loaded at run-time.
After researching this for hours, I thought it was time to resort to stackoverflow as I'm not getting anywhere. I've read numerous articles and none are giving me a correct answer, so I've got a few questions:
How to fix my error?
How to load the xaml model view at run-time programmatically?
How to load the xaml model view at run-time using xaml?
Where to call the loading of the xaml at run-time
The sample data file i.e. SoundViewModelSampleData.xaml, looks like this:
<vm:SoundViewModel
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:Soundboard.ViewModels"
xmlns:mo="clr-namespace:Soundboard.Models">
<vm:SoundViewModel.Animals>
<vm:SoundGroupViewModel Title="Animals Sample">
<vm:SoundGroupViewModel.Items>
<mo:SoundDataModel Title="Animals 1" FilePath="Animals.wav" />
</vm:SoundGroupViewModel.Items>
</vm:SoundGroupViewModel>
</vm:SoundViewModel.Animals>
<vm:SoundViewModel.Cartoons>
<vm:SoundGroupViewModel Title="Cartoons Sample">
<vm:SoundGroupViewModel.Items>
<mo:SoundDataModel Title="Cartoons 1" FilePath="Cartoons.wav" />
<mo:SoundDataModel Title="Cartoons 2" FilePath="Cartoons.wav" />
</vm:SoundGroupViewModel.Items>
</vm:SoundGroupViewModel>
</vm:SoundViewModel.Cartoons>
</vm:SoundViewModel>
The simplest code to load this programmatically that I found was:
string path = #".\SampleData\SoundViewModelSampleData.xaml";
using (System.IO.StreamReader reader = new System.IO.StreamReader(path))
{
SoundViewModel vm = XamlReader.Load(reader.ReadToEnd()) as SoundViewModel;
}
While I'm probably calling it from the wrong location for now, I'm getting the following error:
A first chance exception of type
'System.Windows.Markup.XamlParseException' occurred in
System.Windows.ni.dll
{System.Windows.Markup.XamlParseException: Unknown parser error:
Scanner 2147500037. [Line: 5 Position: 14] at
MS.Internal.XcpImports.CreateFromXaml(String xamlString, Boolean
createNamescope, Boolean requireDefaultNamespace, Boolean
allowEventHandlers, Boolean expandTemplatesDuringParse, Boolean
trimDeclaredEncoding) at
System.Windows.Markup.XamlReader.Load(String xaml) at
Soundboard.ViewModels.SoundViewModel.LoadData()}
Unknown parser error: Scanner 2147500037. [Line: 5 Position: 14]
Assuming I can resolve this error, this would take care of my question 1 & 2 (fixing error and loading the data programmatically)
Can you spot what's causing this problem?
As mentioned above, I'm probably loading this in the wrong place i.e. from within my ViewModel when it is created when the app loads.
namespace Soundboard.ViewModels
{
public class SoundViewModel
{
public SoundGroupViewModel Animals { get; set; }
public SoundGroupViewModel Cartoons { get; set; }
public bool IsDataLoaded { get; set; }
public void LoadData()
{
string path = #".\SampleData\SoundViewModelSampleData.xaml";
using (System.IO.StreamReader reader = new System.IO.StreamReader(path))
{
SoundViewModel vm = System.Windows.Markup.XamlReader.Load(reader.ReadToEnd()) as SoundViewModel;
}
IsDataLoaded = true;
}
}
}
And in my app.xaml.cs I have the following:
public static SoundViewModel SoundViewModel
{
get
{
if (_soundViewModel == null)
{
_soundViewModel = new SoundViewModel();
_soundViewModel.LoadData();
}
return _soundViewModel;
}
}
Now how can I achieve the same using just xaml for the run-time and use d:datacontext for design-time.
I've read a few articles but they are all for wpf but most are related to loading usercontrol, etc.. but not a viewmodel
Any help would be greatly appreciated.
Thanks.
I was busy on a similar problem as yours with XamlReader. I found that you should define the assembly namespace in the root element of your xaml file even if it is included in the same assembly. In the example code below even if the xaml is included in SoundBoard.dll, I declare its namespace in the xaml file.
xmlns:vm = "clr-namespace:SoundBoard.ViewModels;assembly=SoundBoard">
Also tried doing this and the best I could come up with was to move the data XAML file to assets, mark it as a Resource (I removed the Custom Tool as well), and then load it with the following:
public void LoadData()
{
// Load data
//LoadCodeData();
LoadXamlData();
IsDataLoaded = true;
}
private void LoadXamlData()
{
string path = "SoundBoard;component/assets/runtimecontent/SampleData.xaml";
Uri uri = new Uri(path, UriKind.Relative);
using (System.IO.StreamReader reader = new System.IO.StreamReader((System.Windows.Application.GetResourceStream(uri)).Stream))
{
SoundModel model = System.Windows.Markup.XamlReader.Load(reader.ReadToEnd()) as SoundModel;
this.Animals = model.Animals;
this.Cartoons = model.Cartoons;
this.Taunts = model.Taunts;
this.Warnings = model.Warnings;
this.CustomSounds = model.CustomSounds;
}
}
I also did what Bahti suggested.

C# Web Service XmlSerializer issue

I have a C# Web Service that is serializing my simple class:
[Serializable]
[XmlInclude(typeof(Bitmap))]
[XmlTypeAttribute(Namespace = "http://tempuri.org/")]
public class Class1
{
private static Bitmap _myImage = new Bitmap(#"C:\WebApplication1\ClassLibrary1\Untitled.png");
public Bitmap MyImage
{
get { return _myImage; }
set
{
_myImage = value;
}
}
}
Here's the asmx.cs code that does the serialization:
[WebMethod]
public string HelloWorld()
{
var c = new Class1();
XmlSerializer serializer = new XmlSerializer(typeof(Class1));
return XMLSerializer(c);
}
public string XMLSerializer(object pObject)
{
try
{
XmlSerializer xs = new XmlSerializer(pObject.GetType());
using (StringWriter stream = new StringWriter())
{
xs.Serialize(stream, pObject);
stream.Flush();
return stream.ToString();
}
}
catch (Exception ex)
{
return ex.ToString();
}
}
Looks prety straight forward. However, the XML generated by the XmlSerializer is producing and error when I try to DeSerialize it.
{"There is an error in XML document (5, 5)."}
{"Parameter is not valid."}
When I try to load the generated XML into IE I get this error.
Switch from current encoding to specified encoding not supported. Error processing resource 'file:///C:/Users/mhall15/Deskt...
<?xml version="1.0" encoding="utf-16"?>
Here's the generated XML:
<?xml version="1.0" encoding="utf-16"?>
<Class1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MyImage xmlns="http://tempuri.org/">
<Palette />
</MyImage>
</Class1>
Any ideas what's going on?
During the serialization, replace "encoding="utf-16" with "encoding="utf-8"" and that will cut it. The source of the problem - I'm not sure, but I've ran into it numerous times, and that's how I dealt with it.
That's how to deal with the IE issue.
The deserialization should be amongst these lines. I'm posting the kind of arbitrary code I normally use:
public static object DeserializeFromXML<T>(string _input)
{
object _temp = Activator.CreateInstance<T>();
Type expected_type = _temp.GetType();
_temp = null;
XmlSerializer serializer = new XmlSerializer(expected_type);
StringReader stringWriter = new StringReader(_input);
object _copy = serializer.Deserialize(stringWriter);
return _copy;
}
In the above example, I'm using templating for reusability sake. You should be able to call the method by saying DeserializeFromXML < Class1 >(_xml_input) where xml input is the string. That will force the compiler to use the definition of the given class to deserialize the XML input. That way you wouldn't even have to change the encoding in the serialization. If it's also a case where you may or may not know the data type to deserialize with, you can use a strategy design pattern where you register the root type of the XML with it's associated generic type. Later on you can reference that registry and arbitrarily deserialize any XML input as long as the root type is registered. It's a trick i normally use as well. If more is needed on this, let me know, and I'll explain in detail.
In addition,if you are running IE 9, the new update to IE 9 makes it difficult to view XML. Press F12 - go to developer tools and change your browser mode to run as IE 8 instead of IE 9.

XmlSerializer giving FileNotFoundException at constructor

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]);
}
}

Custom Trace Listener with the Enterprise Application Blocks

The project I'm currently working on uses Enterprise Libraries V3.1 framework for logging.
I need to take the log file that's generated and archive it off at specific points. The built in Trace Listeners seem to keep the file open in-between logging events. I've set up a custom Trace Listener which will append to a file and close it, so that the file is always shiftable.
It looks like this (minus error handling for clarity):
[ConfigurationElementType(typeof(CustomTraceListenerData))]
public class AlwaysClosedTextFileTraceListener : CustomTraceListener
{
private string logFilePath;
public AlwaysClosedTextFileTraceListener ()
{
logFilePath = #"hardcodedpath\log.txt";
}
public override void Write(string message)
{
using (StreamWriter logFile = File.AppendText(logFilePath))
{
logFile.Write(message);
logFile.Flush();
logFile.Close();
}
}
public override void WriteLine(string message)
{
using (StreamWriter logFile = File.AppendText(logFilePath))
{
logFile.WriteLine(message);
logFile.Flush();
}
}
public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data)
{
if (data is LogEntry && this.Formatter != null)
{
WriteLine(this.Formatter.Format(data as LogEntry));
}
else
{
WriteLine(data.ToString());
}
}
}
This works fine, but I'd much rather be passing in the path as a parameter somehow, rather than hardcoding it.
For fun, I tried adding it to the constructor, to see what happens:
public LogFolderTraceListener(string logFilePath)
{
this.logFilePath = logFilePath;
}
When I do this, I get returned an error message hinting towards what I'm doing wrong:
System.InvalidOperationException : The type 'AlwaysClosedTextFileTraceListener' specified for custom trace listener named 'MyLogFile' does not a default constructor, which is required when no InitData is specified in the configuration.
From here on in, my investigations have very much come to, the opposite of dead ends, infinite probability problems.
I have found this thumbing through the source code for the inbuilt RollingTraceListener
There is a class RollingFlatFileTraceListenerData : TraceListenerData which seems to contain all the settings passed into the constructor
Camped out at the bottom of the file for RollingFlatFileTraceListenerData is the class RollingTraceListenerAssembler : TraceListenerAsssembler which seems to be a factory
There is another class SystemDiagnosticsTraceListenerNode : TraceListenerNode which seems to make the Data class presentable to the configuration application
My question is this: how do I create a CustomTraceListener with a configurable parameter of path?
The CustomTraceListener derives from TraceListener, this has a StringDictionary called Attributes.
This will contain all the attributes in the configuration line for your TraceListener and can be gotten out by name, eg.
string logFileName= Attributes["fileName"]
I suspect that perhaps the Enterprise Application Blocks although (probably) wonderful, seem unnecessarily complicated and ultimately more trouble than their worth for this kind of customisation.
the problem is typical microsoft .. (add your own adjectives here) ..
1) when you add a custom trace listener, the 'raw' app.config statement added is:
name="Custom Trace Listener" initializeData="" formatter="Text Formatter" />
2) notice the 'initializeData' - this is what the cryptic error message is calling'InitData'.
3) So what its all saying is that you need to have a constructor that accepts initialization data - in vb parlance:
sub new (byval initstuff as string)
4) OR remove the 'initializeData=""' and have a default constructor:
sub new()
I suspect the P&P folks live in a bubble.
riix.
For what it is worth this is how I implemented it. In my this.buildCurrPath() I can read from a config file or in this case I just get the "launch pad" for the web app. But it works fine for me. I have not put it into any production code yet, but it should go out soon.
[ConfigurationElementType(typeof(CustomTraceListenerData))]
public class CustomListener: CustomTraceListener
{
#region Fields (3) 
private int logSize;
StreamWriter sw;
#endregion Fields 
#region Constructors (1) 
public CustomListener ():base()
{
string startPath = this.buildCurrPath();
sw = new StreamWriter(startPath + "\\Logs\\test.log");
sw.AutoFlush = true;
}
I have just had the same issue (except with Enterprise Library v4.1).
The solution I've found is to remove the default constructor and the only have a constructor with a string parameter for the filename i.e.
public AlwaysClosedTextFileTraceListener (string pathParameter)
{
logFilePath = pathParameter;
}
Then in the app.config put your path in the initializeData parameter
<add ... initializeData="C:\Logs\myLog.log" />
Whilst this isn't recognised by the Entriprise Library configuration editor and isn't as neat as it could be, it works as long as there is only one parameter.
If someone works out how to do it properly, please post and let us know - it's not supposed to be this difficult, surely.

Categories

Resources