I generate a runtime class using reflection.emit, the generation of the class seems to be fine as it shows in ILSpy:
using indice.Edi.Serialization;
using IQoneEDIParser.Formats;
using System;
using System.Xml.Serialization;
[XmlRoot("CONTRL"), XmlType("CONTRL")]
[Serializable]
public class CONTRL : FormatBase
{
private string _syntaxkennung;
private int _sintaxversion;
private string _absenderid;
private string _absendercodeunb;
private string _empfängerid;
private string _empfängercodeunb;
private string _dokumentdatum;
private string _dokumentzeit;
private string _datenaustauschreferenz;
[EdiValue("X(4)", "UNB/0"), XmlElement("Syntaxkennung", typeof(string))]
public string Syntaxkennung
{
get
{
return this._syntaxkennung;
}
set
{
this._syntaxkennung = value;
}
}
[EdiValue("9(1)", "UNB/0/1"), XmlElement("Sintaxversion", typeof(int))]
public int Sintaxversion
{
get
{
return this._sintaxversion;
}
set
{
this._sintaxversion = value;
}
}
[EdiValue("X(35)", "UNB/1/0"), XmlElement("AbsenderID", typeof(string))]
public string AbsenderID
{
get
{
return this._absenderid;
}
set
{
this._absenderid = value;
}
}
[EdiValue("X(4)", "UNB/1/1"), XmlElement("AbsenderCodeUNB", typeof(string))]
public string AbsenderCodeUNB
{
get
{
return this._absendercodeunb;
}
set
{
this._absendercodeunb = value;
}
}
[EdiValue("X(35)", "UNB/2/0"), XmlElement("EmpfängerID", typeof(string))]
public string EmpfängerID
{
get
{
return this._empfängerid;
}
set
{
this._empfängerid = value;
}
}
[EdiValue("X(4)", "UNB/2/1"), XmlElement("EmpfängerCodeUNB", typeof(string))]
public string EmpfängerCodeUNB
{
get
{
return this._empfängercodeunb;
}
set
{
this._empfängercodeunb = value;
}
}
[EdiValue("X(6)", "UNB/3/0"), XmlElement("Dokumentdatum", typeof(string))]
public string Dokumentdatum
{
get
{
return this._dokumentdatum;
}
set
{
this._dokumentdatum = value;
}
}
[EdiValue("X(4)", "UNB/3/1"), XmlElement("Dokumentzeit", typeof(string))]
public string Dokumentzeit
{
get
{
return this._dokumentzeit;
}
set
{
this._dokumentzeit = value;
}
}
[EdiValue("X(14)", "UNB/4/0"), XmlElement("Datenaustauschreferenz", typeof(string))]
public string Datenaustauschreferenz
{
get
{
return this._datenaustauschreferenz;
}
set
{
this._datenaustauschreferenz = value;
}
}
}
For any unknown reason, the only property getting serialized to Xml is the Syntaxversion (the only one which is Type Integer)
Here the serialization method:
public static String SerializeToXml(FormatBase toSerialize, Type inType)
{
XmlWriterSettings xmlSettings = new XmlWriterSettings
{
Encoding = Encoding.UTF8,
Indent = true,
OmitXmlDeclaration = true,
NewLineOnAttributes = true,
CloseOutput = true
};
using (StringWriter stringWriter = new StringWriter())
{
XmlSerializer serializer2 = new XmlSerializer(inType);
using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter, xmlSettings))
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
serializer2.Serialize(xmlWriter, toSerialize, ns);
return stringWriter.ToString();
}
}
}
Any Ideas about why the rest of properties are not getting serialised? Thanks in advance!
EDIT_1:
After further tests I copy-paste the generated class and created it as a "normal" type in my project, try again the Serialization method, and work as expected (See EDIT_2)
Can it be a Reflection.Emit problem and/or my runtime assembly?
EDIT_2:
Expected result from the Xml Serialization:
<CONTRL>
<Syntaxkennung>UNOC</Syntaxkennung>
<Sintaxversion>3</Sintaxversion>
<AbsenderID>9904325000003</AbsenderID>
<AbsenderCodeUNB>500</AbsenderCodeUNB>
<EmpfängerID>9900080000007</EmpfängerID>
<EmpfängerCodeUNB>500</EmpfängerCodeUNB>
<Dokumentdatum>161007</Dokumentdatum>
<Dokumentzeit>1723</Dokumentzeit>
</CONTRL>
Received:
<CONTRL>
<Sintaxversion>3</Sintaxversion>
</CONTRL>
I end up implementing IXmlSerializable in the FormatBase (Base class)
public void WriteXml(XmlWriter writer)
{
foreach (PropertyInfo property in GetType().GetProperties())
{
writer.WriteElementString(property.Name, property.GetValue(this)?.ToString());
}
}
And working as expected.
Related
I have a wpf app with an xml Config File.
I made a ViewModel class who is Binded to the MainWindow.xaml, and I'm making some validators using IDataErrorInfo and a ValidationRule class.
What I want is, if the user changes a value, and the value passes the validation, the config class becomes serialized to xml.
For the save I have a class extension:
public static class ConfiguracionExtension
{
public static void Save(this Configuration configXML)
{
string ConfigPath = AppDomain.CurrentDomain.BaseDirectory + "config.xml";
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
XmlSerializer serializer = new XmlSerializer(typeof(Configuration));
Stream writer = new FileStream(ConfigPath, FileMode.Create);
ns.Add("", "");
serializer.Serialize(writer, configXML, ns);
writer.Close();
}
}
The configuration class looks like:
[Serializable, XmlRoot("configuration")]
public class Configuration : IDataErrorInfo, INotifyPropertyChanged
{
private int _minute;
[XmlElement]
public int minute
{
get
{
return _minute;
}
set
{
_minute = value;
OnPropertyChanged("minute");
}
}
public static Configuration Load()
{
string ConfigPath= AppDomain.CurrentDomain.BaseDirectory + "config.xml";
if (File.Exists(ConfigPath))
{
try
{
XmlSerializer _s = new XmlSerializer(typeof(Configuration));
return (Configuration)_s.Deserialize(new XmlTextReader(ConfigPath));
}
catch (Exception ex)
{
Auxiliar.writeError(ex.ToString());
return new Configuration();
}
}
else
return new Configuration();
}
public Configuracion()
{
minutes = 60;
}
#region IDataErrorInfo Members
public string Error
{
get { return String.Empty; }
}
public string this[string columnName]
{
get
{
String errorMessage = String.Empty;
switch (columnName)
{
case "minute":
if (minute < 1)
{
errorMessage = "minutes can't be less than 1";
}
break;
}
return errorMessage;
}
}
#endregion
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(String propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
and the validation rule looks like:
public class MinutesValidation : ValidationRule
{
private int _min;
public int Minimum
{
get { return _min; }
set { _min = value; }
}
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
int minute;
Boolean noIllegalChars;
noIllegalChars = int.TryParse(value.ToString(), out minute);
if (value.ToString().Length < 1)
{
return new ValidationResult(false, "Value can't be empty");
}
else if (noIllegalChars == false)
{
return new ValidationResult(false, "Ilegal Character");
}
else
{
return new ValidationResult(true, null);
}
}
}
Ok, I Solved, but if anyone gets a better option I'll be very greatful.
What I've done is on the config file I added a loaded boolean who starts on false, and I added a condition to the save function to work only when the loaded is true.
The config class now is like this:
[Serializable, XmlRoot("configuration")]
public class Configuration : IDataErrorInfo, INotifyPropertyChanged
{
private int _minute;
[XmlElement]
public int minute
{
get
{
return _minute;
}
set
{
_minute = value;
this.Save();
OnPropertyChanged("minute");
}
}
[XmlIgnore]
public bool loaded;
public static Configuration Load()
{
string ConfigPath= AppDomain.CurrentDomain.BaseDirectory + "config.xml";
if (File.Exists(ConfigPath))
{
try
{
XmlSerializer _s = new XmlSerializer(typeof(Configuration));
var tempConf = (Configuracion)_s.Deserialize(new XmlTextReader(ConfigPath));
tempConf.loaded = false;
return tempConf;
}
[...]
}
public Configuracion()
{
loaded = false;
minutes = 60;
}
[...]
}
I added a loaded event to the main window, and when it's fired it sets the loaded property to true.
I'm working on xml generation using list to direct xml of generic class, but getting wrong result of xml.
I want below output from XmlSerializer.
<root>
<rating city="A" code="A1">A++</rating>
<rating city="B" code="A2">A</rating>
<rating city="C" code="A3">AB</rating>
</root>
currently i'm getting this
<ratings reason="reason123">
<rating>R</rating>
</ratings>
<ratings reason="reason123">
<rating>R</rating></ratings>
C# Code
public class root
{
[XmlAttribute("city")]
public string city { get; set; }
[XmlAttribute("code")]
public string code { get; set; }
[XmlElement("rating")]
public string rating { get; set; }
}
string tempXML6 = XmlExtensions.Serialize(rootList)
static public void Serialize(object classobject)
{
XmlSerializer SerializedObject = new XmlSerializer(classobject.GetType());
using (MemoryStream xmlStream = new MemoryStream())
{
SerializedObject.Serialize(xmlStream, classobject);
xmlStream.Position = 0;
//Loads the XML document from the specified string.
XmlDocument resultDocument = new XmlDocument();
resultDocument.Load(xmlStream);
if (!string.IsNullOrEmpty(resultDocument.DocumentElement.InnerXml))
{
return resultDocument.DocumentElement.InnerXml;
}
else
{
return string.Empty;
}
}
}
please let me know what's needs to be change.
Your object model is wrong. It should be something like this.
[XmlRoot("root")]
public class Root
{
[XmlElement("rating")]
public Rating[] Ratings { get; set; }
}
public class Rating
{
[XmlAttribute("city")]
public string City { get; set; }
[XmlAttribute("code")]
public string Code { get; set; }
[XmlText]
public string Value { get; set; }
}
To serialize the object do this
Root root = new Root
{
Ratings = new Rating[]
{
new Rating { City = "A", Code = "A1", Value = "A++" },
new Rating { City = "B", Code = "A2", Value = "A" },
new Rating { City = "C", Code = "A3", Value = "AB" }
}
};
string serializedObject = Serialize(root);
This is the serialize method
public static string Serialize<T>(T item)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (StringWriter stringWriter = new StringWriter())
{
using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter, new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true }))
{
serializer.Serialize(xmlWriter, item, new XmlSerializerNamespaces(new[] { new XmlQualifiedName(string.Empty, string.Empty) }));
}
return stringWriter.ToString();
}
}
Xml output
<root>
<rating city="A" code="A1">A++</rating>
<rating city="B" code="A2">A</rating>
<rating city="C" code="A3">AB</rating>
</root>
Please Change your Class defination to like this:
[XmlTypeAttribute(AnonymousType = true)]
[XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class root
{
private rootRating[] ratingField;
[XmlElementAttribute("rating")]
public rootRating[] rating
{
get
{
return this.ratingField;
}
set
{
this.ratingField = value;
}
}
}
[XmlTypeAttribute(AnonymousType = true)]
public partial class rootRating
{
private string cityField;
private string codeField;
private string valueField;
[XmlAttributeAttribute()]
public string city
{
get
{
return this.cityField;
}
set
{
this.cityField = value;
}
}
[XmlAttributeAttribute()]
public string code
{
get
{
return this.codeField;
}
set
{
this.codeField = value;
}
}
[XmlTextAttribute()]
public string Value
{
get
{
return this.valueField;
}
set
{
this.valueField = value;
}
}
}
//try this
public static XElement SerializeRoot(IEnumerable<root> objRoot)
{
XElement serializedRoot = null;
using (MemoryStream memoryStream = new MemoryStream())
{
using (TextWriter StreamWriter = new StreamWriter(memoryStream))
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<root>));
xmlSerializer.Serialize(StreamWriter, objRoot);
serializedRoot = XElement.Parse(Encoding.UTF8.GetString(memoryStream.ToArray()));
}
}
return serializedRoot;
}
I want to cast a string from xml file to be casted to ContactPersonType
See for loop for where string needs to be casted
public class ContactPersonType
{
private String _id;
public String ID
{
get { return _id; }
set { _id = value; }
}
private String _name;
public String Name
{
get { return _name; }
set { _name = value; }
}
}
//ContactPerson class
private ContactPersonType _jobRole;
public ContactPersonType JobRole
{
get { return _jobRole; }
set { _jobRole = value; }
}
public static ObservableCollection<ContactPerson> getContactPerson()
{
ObservableCollection<ContactPerson> ContactPersons = new ObservableCollection<ContactPerson>();
XmlDocument doc = new XmlDocument();
doc.Load("contactpersoon.xml");
XmlNodeList elemList = doc.GetElementsByTagName("contact");
for (int i = 0; i < elemList.Count; i++)
{
//this needs to be casted to ContactPersonType
contactPerson.JobRole = elemList[i]["jobrole"].InnerText;
}
return ContactPersons;
}
I'm not really familliar with the way you read the XML elements so this code might need some tweaking but this should be along the lines of what you're looking for (also took the liberty of making your properties autoimplemented for higher code readability)
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
namespace Program
{
public class ContactPersonType
{
public string ID { get; set; }
public string Name { get; set; }
}
public class ContactPerson
{
public ContactPersonType JobRole { get; set; }
public static ObservableCollection<ContactPerson> GetContactPerson()
{
var contactPersons = new ObservableCollection<ContactPerson>();
XElement doc = XElement.Load("contactpersoon.xml");
var contacts = doc.Elements("contact");
for (int i = 0; i < contacts.Count(); i++)
{
contactPersons.Add(new ContactPerson
{
JobRole = new ContactPersonType
{
ID = i.ToString(),
Name = contacts.ElementAt(i).Element("jobrole").Value
}
});
}
return contactPersons;
}
}
}
Depending on how you set the ID property you could possibly rewrite the loop as a foreach. For more info on XElement and it's members, check out http://msdn.microsoft.com/en-us/library/system.xml.linq.xelement(v=vs.110).aspx and http://msdn.microsoft.com/en-us/vstudio/bb688087.aspx
Can you not deserialize the XML to the .NET class with a helper such as the one shown below?
public T Deserialize<T>(string fileName)
{
try
{
XmlSerializer sx = new XmlSerializer(typeof(T)); //or T.GetType?
StreamReader sr = new StreamReader(fileName);
var data = sx.Deserialize(sr);
sr.Close();
return (T)data;
}
catch (Exception ex)
{
throw;
}
}
I hate XmlDocument, so always deserialize where possible (though a potential alternative to i do like is XDocument).
EDIT - the usage would be something like:
var item = Deserialize<ContactPersonType>(fileName);
I have a WCF Service hosted on IIS. Here is my Interface:
[ServiceContract]
[SilverlightFaultBehavior]
public interface IETC
{
[OperationContract]
[PrincipalPermission(SecurityAction.Demand, Role = "XYZ")]
string GetStampXML();
[OperationContract]
[PrincipalPermission(SecurityAction.Demand, Role = "XYZ")]
List<Stamp> GetStamps();
}
I am getting an error when I go to my WCF service through the web browser. The error is as follows:
Type 'System.Windows.Media.ImageSource' cannot be serialized. Consider marking it with the DataContractAttribute attribute.....
My stamps Class is:
[DataContract]
public class Stamp
{
private string _Name;
private string _SmallIcon = "";
private string _MediumIcon = "";
private string _LargeIcon = "";
private BitmapImage _SmallImage;
private BitmapImage _MediumImage;
private BitmapImage _LargeImage;
[DataMember]
public string Name
{
get { return _Name; }
set { _Name = value; }
}
[DataMember]
public string SmallIcon
{
get { return _SmallIcon; }
set { _SmallIcon = value; }
}
[DataMember]
public string MediumIcon
{
get { return _MediumIcon; }
set { _MediumIcon = value; }
}
[DataMember]
public string LargeIcon
{
get { return _LargeIcon; }
set { _LargeIcon = value; }
}
[IgnoreDataMember]
public BitmapImage SmallImage
{
get { return _SmallImage; }
set { _SmallImage = value; }
}
[IgnoreDataMember]
public BitmapImage MediumImage
{
get { return _MediumImage; }
set { _MediumImage = value; }
}
[IgnoreDataMember]
public BitmapImage LargeImage
{
get { return _LargeImage; }
set { _LargeImage = value; }
}
}
It is like the IgnoreDataMember is not being recognized. I tried it without the IgnoreDataMember figure it was going to only serialize the DataMembers, and that didn't work either. Any ideas why it seems to trying to serialize the BitmapImage?
What version of .net are you running? .NET 4 Data Contract does not require you to explicitly set Ignore attributes. You can test what's being produced by using DataContractSerializer and writing the content to the file. Create console application and reference your service project.
namespace SO_10281928
{
class Program
{
static void Main(string[] args)
{
var instance = new Stamp
{
Name = "Test",
SmallIcon = "Small Icon",
LargeIcon = "LargeIcon",
MediumIcon = "MediumIcon"
};
using (var stream = new FileStream(#"c:\temp\stamp.xml", FileMode.Create))
{
var ds = new DataContractSerializer(typeof (Stamp));
ds.WriteObject(stream, instance);
}
Console.WriteLine("Done.");
Console.ReadLine();
}
}
[DataContract]
public class Stamp
{
private string _Name;
private string _SmallIcon = "";
private string _MediumIcon = "";
private string _LargeIcon = "";
private BitmapImage _SmallImage;
private BitmapImage _MediumImage;
private BitmapImage _LargeImage;
[DataMember]
public string Name
{
get { return _Name; }
set { _Name = value; }
}
[DataMember]
public string SmallIcon
{
get { return _SmallIcon; }
set { _SmallIcon = value; }
}
[DataMember]
public string MediumIcon
{
get { return _MediumIcon; }
set { _MediumIcon = value; }
}
[DataMember]
public string LargeIcon
{
get { return _LargeIcon; }
set { _LargeIcon = value; }
}
public BitmapImage SmallImage
{
get { return _SmallImage; }
set { _SmallImage = value; }
}
public BitmapImage MediumImage
{
get { return _MediumImage; }
set { _MediumImage = value; }
}
public BitmapImage LargeImage
{
get { return _LargeImage; }
set { _LargeImage = value; }
}
}
public class BitmapImage
{
}
}
And the result is :
<Stamp xmlns="http://schemas.datacontract.org/2004/07/SO_10281928" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<LargeIcon>LargeIcon</LargeIcon>
<MediumIcon>MediumIcon</MediumIcon>
<Name>Test</Name>
<SmallIcon>Small Icon</SmallIcon>
</Stamp>
If i try to serialize an object of the following ClassToSerialize class with System.Runtime.Serialization.Json.DataContractJsonSerializer
[DataContract,Serializable]
public class ClassToSerialize
{
[NonSerialized] private bool _mf;
public bool IsMf
{
get { return _mf};
set{ _mf = value;}
}
[DataMember]
public char PrimaryExc { get; set; }
}
public class TestClass
{
ClassToSerialize obj = new ClassToSerialize{PrimaryExchange = 'a', NoResults = true};
var serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(ClassToSerialize);
var ms = new MemoryStream();
serializer.WriteObject(ms, obj);
return Encoding.UTF8.GetString(ms.ToArray());
}
The return string still contains IsMf property and its value. The NOnSerialized attribute is ignored. Can someone please suggest what attribute to use when using DataContractJsonSerializer so as to not serialize some properties
The following code worked for me (it's almost identical to your's with a few small compilation errors fixed):
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
class Program
{
static void Main()
{
var obj = new ClassToSerialize
{
PrimaryExc = 'a',
NoResults = true
};
var serializer
= new DataContractJsonSerializer(typeof(ClassToSerialize));
var ms = new MemoryStream();
serializer.WriteObject(ms, obj);
Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
}
}
[DataContract]
[Serializable]
public class ClassToSerialize
{
[NonSerialized]
private bool _mf;
public bool IsMf
{
get { return _mf; }
set { _mf = value; }
}
[DataMember]
public bool NoResults { get; set; }
[DataMember]
public char PrimaryExc { get; set; }
}
Output:
{"NoResults":true,"PrimaryExc":"a"}
No, it doesn't contain it. You must be mistaken:
[DataContract]
public class ClassToSerialize
{
[NonSerialized]
private bool _mf;
public bool IsMf
{
get { return _mf; }
set{ _mf = value;}
}
[DataMember]
public char PrimaryExc { get; set; }
}
class Program
{
static void Main()
{
var obj = new ClassToSerialize
{
PrimaryExc = 'a',
IsMf = false
};
var serializer = new DataContractJsonSerializer(obj.GetType());
serializer.WriteObject(Console.OpenStandardOutput(), obj);
}
}
Output:
{"PrimaryExc":"a"}
Remark: You don't need the [Serializable] attribute on your class. That's only for binary serialization.