I get the following error when trying to serialize a generic list
"System.Reflection.RuntimeParameterInfo is inaccessible due to its protection level. Only public types can be processed"
here is my code below
XmlSerializer serializer = new XmlSerializer(typeof(List<System.Reflection.ParameterInfo>));
XDocument document = new XDocument();
using (XmlWriter xmlWriter = document.CreateWriter())
{
serializer.Serialize(xmlWriter, parameterList);
}
return document.Root.ToString();
Not all types are serializable. With a serializer such as XmlSerializer, your best approach is to write a DTO that has the parts that you are interested in, for example:
public class Parameter {
public string Name {get;set;}
public string TypeName {get;set;}
public bool ByRef {get;set;}
}
then populate that from the ParameterInfo, and serialize that. Note that some things are problematic here, for example it would be very inconvenient to serialize a DefaultValue, unless you serialize it as a string and parse it back at the receiver.
Related
Lets say I have the following simple class:
[XmlRoot]
[XmlType("string")]
public partial class eString : IEnumerable<char>
{
string AsString {get;set;}
public IEnumerator<char> GetEnumerator()
{
return this.AsString.ToCharArray().ToList().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.AsString.ToCharArray().GetEnumerator();
}
public void Add(char character)
{
this.AsString += character;
}
}
Also a namedValue class:
[XmlRoot]
public partial class eNamedValue: KeyValuePair<eString,object>
{...}
And finally,
[XmlRoot]
public partial class eList<T>: List<eNamedValue>
{...}
Now, I serialize eList or any class that inherits from eList using the following XML serializer:
public static XDocument Serialize<T>(this T obj) where T: new()
{
Type tt = obj.GetType();
XmlSerializer xsSubmit = new XmlSerializer(tt);
StringWriter sww = new StringWriter();
XmlWriter writer = XmlWriter.Create(sww);
xsSubmit.Serialize(writer, obj);
return XDocument.Parse(sww.ToString());
}
Serialization works - but my eString is being serialized as a character array, so instead of getting "string", I get individual characters values:
<eNamedList>
<Key>99</Key>
<Key>111</Key>
<Key>100</Key>
<Key>101</Key>...
Also, on Deserialization (SOLVED, see Update#1 below):
public static T Deserialize<T>(this XDocument xml) where T: new()
{
var serializer = new XmlSerializer(typeof(T));
T result;
using (TextReader reader = new StringReader(xml.ToString()))
{
result = (T)serializer.Deserialize(reader);
}
return result;
}
I receive the following error:
System.Runtime.Serialization.SerializationException: Error in line 1 position 111. Expecting element 'eNamedList' from namespace 'http://schemas.datacontract.org/2004/07/Epic'.. Encountered 'Element' with name 'eNamedList', namespace ''.
So, my questions become:
How do I control serialization of my eString, or any IEnumerable<char> and always serialize as a string?
Why, when the element names match, do I get a failure on deserialization? (Am I just missing a namespace declaration?)
Thanks!
Update #1:
So, I removed the IEnumerable<char> interface from my eString, and just left the IEnumerable<char>.GetEnumerator() method, which allows my string to be used AS an IEnumerable<char> while in a foreach loop, but serializes as a string. #WIN
Also, thanks to dbc, updated the original post with the XML Deserializer (rather than DataContract Serializer) and deserialization works.
To answer your questions:
You probably shouldn't reinvent the wheel with custom string solutions. Regardless, if you want an (insanely) high-level of control over your (de-)serialization, you could implement IXmlSerializable and do the exact same thing yourself.
[XmlRoot("string-wrapper")]
public class CustomString : IXmlSerializable
{
public string Value { get; set; }
public XmlSchema GetSchema()
{
return null; // GetSchema should not be used.
}
public void ReadXml(XmlReader reader)
{
reader.MoveToContent();
bool isEmpty = reader.IsEmptyElement;
reader.ReadStartElement();
if (!isEmpty)
{
Value = reader.ReadString();
reader.ReadEndElement();
}
}
public void WriteXml(XmlWriter writer)
{
writer.WriteString(Value);
}
}
Serialization of a CustomString now yields <string-wrapper>Testing</string-wrapper>. I'll post some test code at the end of this post.
Your deserialization is likely broken because the XmlSerializer doesn't know that the IEnumerable you marked serializable should actually be treated like a string.
And now... Forget what I just told you. Unless you have very specific formatting requirements you should not implement your own version of a string. The built-in formatter knows a lot more formatting tricks (http://www.w3.org/TR/xmlschema-2/#built-in-datatypes), so you should probably let it do it's job.
Serializing classes is where the attributes come in, though I recommend you switch to the WFC data contracts, which may sound scary at first but actually provides a whole lot more for a lot less code. Again, I'm not sure what you're trying to accomplish, but trust me you don't want to get into the habit of hand writing XML.
If you're up for it you might like dynamic objects and the ExpandoObject (http://www.codeproject.com/Tips/227139/Converting-XML-to-an-dynamic-object-using-ExpandoO). These eliminate types all together and allow you to create dictionaries, arrays, named properties, whatever, all on the fly!
Finally, easy on the generics! Deserializing generic classes is not a trivial task. Besides, you probably don't need to. If you want your own collections, try the System.Collections.ObjectModel namespace. You don't have to worry about maintaining lists and implementing interfaces, just what you're actually storing:
class DictionaryOfStringsAndObjects : KeyedCollection<string, object {...}
class CollectionOfStrings : Collection<string> {...}
Also, try to avoid partial classes unless an ORM or a large legacy class forces it on you. You shouldn't actually use them unless you're made to.
All the best, and to a future devoid of XML!
public class CustomSerializer
{
public static void Test()
{
var obj = new CustomString {Value = "Random string!"};
var serializer = new CustomSerializer();
var xml = serializer.Serialize(obj);
Console.WriteLine(xml);
var obj2 = serializer.Deserialize<CustomString>(xml);
}
public string Serialize(object obj)
{
var serializer = new XmlSerializer(obj.GetType());
using (var io = new StringWriter())
{
serializer.Serialize(io, obj);
return io.ToString();
}
}
public T Deserialize<T>(string xml)
{
var serializer = new XmlSerializer(typeof (T));
using (var io = new StringReader(xml))
{
return (T)serializer.Deserialize(io);
}
}
}
I hope to find a solution from you. What I need is to serialize ValidatorList class object into an xml document. How to do this?
I tried like this:
XmlSerializer _serializer = new XmlSerializer(list);
But I don't know how to make output of xml for list that has several classes.
C#
_list= new ListVal();
Type _type = typeof(ras);
_list.Add(new RequiredField
{
Property = _type.GetProperty("CustRef")
}.Add(new AsciiVal()));
_list.Add(new RequiredField
{
Property = _type.GetProperty("ctr")
}.Add(new StringLengthVal
{
min= 3,
max= 3
}));
[Serializable]
public class Field
{
public Field Next
{
get;
set;
}
public Field TypeName
{
get;
set;
}
public Field PropertyName
{
get;
set;
}
}
public class RequiredField : Field
{
//TODO
}
public class AsciiVal: Field
{
//TODO
}
public class StringLengthVal: Field
{
//TODO
}
public class ListVal: List<Field>
{
//TODO
}
I have something close, but not exactly the Xml you want. In actual fact I think you'll see that the Xml produced below makes a bit more sense than what you have.
To get you started, you control the serialization and deserialization using attributes in the System.Xml.Serialization namespace. A few useful ones to read up on are
XmlRootAttribute
XmlElementAttribute
XmlAttributeAttribute
XmlIncludeAttribute
So I mocked up some code which closely matches your own. Notice the addition of some attributes to instruct the serializer how I want the Xml to be laid out.
[XmlInclude(typeof(AsciiValidator))]
[XmlInclude(typeof(RequiredValidator))]
[XmlInclude(typeof(StringLengthValidator))]
public class FieldValidator
{
[XmlElement("Next")]
public FieldValidator Next
{
get;
set;
}
[XmlElement("PropertyName")]
public string PropertyName
{
get;
set;
}
}
public class AsciiValidator: FieldValidator
{
}
public class RequiredValidator: FieldValidator
{
}
public class StringLengthValidator: FieldValidator
{
[XmlElement]
public int MinLength{get;set;}
[XmlElement]
public int MaxLength{get;set;}
}
[XmlRoot("ValidatorList")]
public class ValidatorList : List<FieldValidator>
{
}
Point of interest; Every class inheriting FieldValidator must be added to the list of known types using XmlIncludeAttribute so the serializer knows what to do with them)
Then I created an example object map:
var test = new ValidatorList();
test.Add(
new RequiredValidator()
{
PropertyName="CustRef",
Next = new AsciiValidator()
});
test.Add(
new RequiredValidator()
{
PropertyName="CurrencyIndicator",
Next = new StringLengthValidator(){
MinLength=3,
MaxLength = 10
}
});
Finally I told the serializer to serialize it (and output the result to the console)
var ser = new XmlSerializer(typeof(ValidatorList));
ser.Serialize(Console.Out,test);
This was the result:
<?xml version="1.0" encoding="utf-8"?>
<ValidatorList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<FieldValidator xsi:type="RequiredValidator">
<Next xsi:type="AsciiValidator" />
<PropertyName>CustRef</PropertyName>
</FieldValidator>
<FieldValidator xsi:type="RequiredValidator">
<Next xsi:type="StringLengthValidator">
<MinLength>3</MinLength>
<MaxLength>10</MaxLength>
</Next>
<PropertyName>CurrencyIndicator</PropertyName>
</FieldValidator>
</ValidatorList>
Not a million miles away from what you wanted. There is the need to output certain things in a certain way (eg xsi:type tells the serializer how to deserialize back to the object map). I hope this gives you a good start.
Here is a live, working example: http://rextester.com/OXPOB95358
Deserialization can be done by calling the Deserialize method on the XmlSerializer.
For example, if your xml is in a string:
var ser = new XmlSerializer(typeof(ValidatorList));
var test = "<..../>" // Your Xml
var xmlReader = XmlReader.Create(new StringReader(test));
var validatorList = (ValidatorList)ser.Deserialize(xmlReader);
There are many overrides of Deserialize which take differing inputs depending if the data is in a Stream an existing reader, or saved to a file.
You have to decorate the class that contains the _validators field with the KonwnType attribute
[Serializable]
[KwownType(typeof(RequiredFieldValidator)]
[KwownType(typeof(AsciValidator)]
public class MySerialisableClass
I have several SO answers that detail how to serialize objects using XML. I'll provide links below.
However, since you're looking for a rather simple serialization of your object, you may want to read up on the DataContractSerializer. It's much less complicated than the old .NET 1.x XML Serialization.
Here's the list of SO answers:
Omitting all xsi and xsd namespaces when serializing an object in .NET?
XmlSerializer: remove unnecessary xsi and xsd namespaces
Suppress xsi:nil but still show Empty Element when Serializing in .Net
Using XmlAttributeOverrides on Nested Properties
Even though many of these have to do with XML serialization and namespaces, they contain complete examples of serializing an object to XML using .NET 1.x XML Serialization.
I have the following class and data members (plus irrelevant methods) I am new to XML and .NET (that excuse is getting old though) and have spent a couple of days reading the MSDN entries (and whatever google turned up) for first XMLReader, then XMLDocument and now XDocument, XElement and XNode but am no closer to a concrete solution to serializing my class (perhaps I need to study serialization in .NET in more depth). To get me started I have some data in an XML file that I want to read (although it prolly is in the wrong format) in to initialize a class to initialize my application. The configuration class is as follows:
class IWantToFile
{
class DirsAndFiles
{
public List<string> Suffixes;
public string Dir;
}
enum OPOptsEnum
{
op1Description, op2Description, op3Description, op4Description,
op5Description, op6Description, op7Description, op8Description,
};
List<DirsAndFiles> ProjectDirs;
bool[] OPOpts = new bool[(int)OPOptsEnum.op8Description + 1];
bool otherOpt;
}
Observing the one to one and one to many relationships therein (eg List<DirsAndFiles> ProjectDirs) can someone please give concise methods to read and write this data to a file? It would greatly assist my development in these fields.
I've got as far as:
if (File.Exists(SPECFILENAME)) {
XDocument xdoc = XDocument.Load(SPECFILENAME);
//Ummm.....
}
but then my lack of .NET XML and Linq exeperience fail me.
I think you might want to use the XmlSerializer, which 'Serializes and deserializes objects into and from XML documents'?
See How to serialize an object to XML by using Visual C# for sample code.
[Serializable]
public class MyObject
{
public string SerializeMe { get; set; }
[XmlIgnore]
public string DONTSerializeMe { get; set; }
}
Helper....
public static class SerializerHelper<T>
{
public static string Serialize(T myobject)
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
StringWriter stringWriter = new StringWriter();
xmlSerializer.Serialize(stringWriter, myobject);
string xml = stringWriter.ToString();
return xml;
}
public static T Deserialize(string xml)
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
StringReader stringReader = new StringReader(xml);
return (T)xmlSerializer.Deserialize(stringReader);
}
}
Usage
MyObject myObject = new MyObject();
string xml = SerializerHelper<MyObject>.Serialize(myObject);
MyObject DeserializedObject = SerializerHelper<MyObject>.Deserialize(xml);
.net, C#
Is it easily possible (by use of attributes etc) to automatically save the entire XML string (as a string field) that was created when an object was serialised when that object is deserialised?
I ask because I'm receiving an XML stub from a web service, and that stub contains a digital signature that I can use to verify the XML. I can deserialise the XML into a useful object that can be passed down into my application layer for verification, but I need the XML too. Ideally my new object would have an OriginalXML property or something. I could verify the XML at a higher level but it's not so convenient for me.
Cheers,
Chris.
You can load the XML file into a string, no problem. But the OriginalXML property would have to be marked with the [NonSerialized] attribute, because you don't want to store that string when you serialize. You'll have to deserialize, reload as an XmlDocument, and store the resulting string to that property.
XmlDocument xmlDoc = new XmlDocument();
try {
xmlDoc.Load(serializedFile);
}
catch (XmlException exc) {
// Handle the error
}
StringWriter stringWriter = new StringWriter();
XmlTextWriter xmlWriter= new XmlTextWriter(stringWriter);
xmlDoc.WriteTo(xmlWriter);
myObject.OriginalXML = xmlWriter.ToString();
HTH,
James
How about
[DataContract]
class FooBar
{
//this property doesn't have the DataMember attribure
//and thus won't be serialized
public string OriginalXml { get; set; }
[DataMember] private int _foo;
[DataMember] private string _bar;
static public FooBar Deserialize(XmlReader reader)
{
var fooBar =
(FooBar)new DataContractSerializer(typeof(FooBar)).ReadObject(reader);
fooBar.OriginalXml = reader.ToString();
return fooBar;
}
}
I created a custom control in XAML, and added some custom properties as well. Now, I want to serialize it to JSON if possible. Here is (essentially) what I have:
public partial class MyCustomClass : UserControl
{
public Dictionary<char, int[]> ValueMap;
public int Value { get; set; }
}
And in the code that handles serialization:
public static string Serialize(object objectToSerialize)
{
using (MemoryStream ms = new MemoryStream())
{
DataContractJsonSerializer serializer =
new DataContractJsonSerializer(objectToSerialize.GetType());
serializer.WriteObject(ms, objectToSerialize);
ms.Position = 0;
using (StreamReader reader = new StreamReader(ms))
return reader.ReadToEnd();
}
}
However, serializer.WriteObject(ms, objectToSerialize); throws
System.Runtime.Serialization.InvalidDataContractException:
Consider marking it with the
DataContractAttribute attribute, and
marking all of its members you want
serialized with the
DataMemberAttribute attribute.
Alternatively, you can ensure that the
type is public and has a parameterless
constructor - all public members of
the type will then be serialized, and
no attributes will be required."
Now, when I do add those attributes to the MyCustomClass, I of course get the same exception, only this time for System.Windows.UIElement instead of MyCustomClass.
So, is there a way to serialize my custom derived class with the existing serialization method, or should I just write a custom serialization methods for MyCustomClass?
I think you are better off implementing IXmlSerializable here, as you really don't want to indiscriminately serialize everything in the base class (and I don't believe you can, quite frankly).
Rather, implement IXmlSerializable on MyCustomClass, and then the DataContractJsonSerializer will be able to use that implementation to serialize to/from JSON.