I have a XML document with a node like this.
<channel id="3102" platform = "1" activation="30/11/2010" desactivation="">
And I want to deserialize it using DataContract and Data Member attributes, which are working well with its properties but are not deserializing the attributes.
[DataContract(Namespace="")]
[XmlSerializerFormat]
public abstract class Channel
{
#region variables privadas
[DataContract(Namespace="")]
[XmlSerializerFormat]
//[KnownType(typeof(AudioChannel))]
//[KnownType(typeof(VideoChannel))]
public abstract class Channel
{
#region variables privadas
private DateTime _desactivation;
private DateTime _activation;
private int _platform;
private int _id;
....
#endregion
#region Propiedades públicas
[DataMember]
[XmlAttribute(AttributeName="desactivation")]
public DateTime Desactivation
{
get { return _desactivation; }
set { _desactivation = value; }
}
[DataMember]
[XmlAttribute(AttributeName="activation")]
public DateTime Activation
{
get { return _activation; }
set { _activation = value; }
}
[DataMember]
[XmlAttribute(AttributeName="platform")]
public int Platform
{
get { return _platform; }
set { _platform = value; }
}
#endregion
#region Propiedades públicas
[DataMember]
[XmlAttribute(AttributeName="desactivation")]
public DateTime Desactivation
{
get { return _desactivation; }
set { _desactivation = value; }
}
[DataMember]
[XmlAttribute(AttributeName="activation")]
public DateTime Activation
{
get { return _activation; }
set { _activation = value; }
}
[DataMember]
[XmlAttribute(AttributeName="platform")]
public int Platform
{
get { return _platform; }
set { _platform = value; }
} ...
My properties associated to these attributes are not filled, what I'm doing wrong?
Thanks in advance for any help provided.
Repeated question. How can you control .NET DataContract serialization so it uses XML attributes instead of elements? You can't do that with a DataContractSerializer, but you should achieve what you ask for using the XmlSerializer.
Related
Hei all,
I noticed a strange behavior of my SOAP Webservice.
When sending the request via soap ui i filled every property of the object.
While debugging the webservice only a few properties where filled.
It seems the top 5 properties, out of 15, are filled. When switching the properties in the Soap request, again the top 5 are filled.
Does anyone have a clue, why the serializing of the request object is not working ?
The interfaces are defined as OperationContract , properties and the request class as DataMember / DataContract.
Here is the Request Class
[DataContract]
public class Article
{
[DataMember]
public String ArticleName
{
get { return _ArticleName; }
set { _ArticleName = value; }
}
[DataMember]
public String Description
{
get { return _Description; }
set { _Description = value; }
}
[DataMember]
public Int ProductSubGroupNumber
{
get { return _ProductSubGroupNumber; }
set { _ProductSubGroupNumber = value; }
}
[DataMember]
public Double ArticleNumber
{
get { return _ArticleNumber; }
set { _ArticleNumber = value; }
}
[DataMember]
public Int Color
{
get { return _Color; }
set { _Color = value; }
}
[DataMember]
public Double Quantity
{
get { return _Quantity; }
set { _Quantity = value; }
}
[DataMember]
public Int Version
{
get { return _Version; }
set { _Version = value; }
}
[DataMember]
public Int Material
{
get { return _Material; }
set { _Material = value; }
}
[DataMember]
public Int Warehouse
{
get { return _Warehouse; }
set { _Warehouse = value; }
}
}
And the Soap Request
<CreateArticle>
<ArticleGroup>1232456789</ArticleGroup>
<Articles>
<Article>
<ArticleName>test</ArticleName>
<Description>TEST 1213123</Description>
<ProductSubGroupNumber>987654</ProductSubGroupNumber>
<ArticleNumber>12345</ArticleNumber>
<Color>0</Color>
<Quantity>1</Quantity>
<Material>0</Material>
<Warehouse>0</Warehouse>
<Version>0</Version>
</Article>
</Articles>
</CreateArticle>
In the debugger are only Attributes till Color filled - the rest is Null.
If I swap them in the request, other are Filled and others not.
The Request Contains a ArticleGroupID as Int and an Array of Articles.
It looks like this is DataContractSerializer's fussy "order" enforcement. It really really wants to know what order the data will be in. You could try educating it:
[DataMember(Order=0)]
public string ArticleName {get;set;}
[DataMember(Order=1)]
public string Description {get;set;}
[DataMember(Order=2)]
public int ProductSubGroupNumber {get;set;}
[DataMember(Order=3)]
public double ArticleNumber {get;set;}
[DataMember(Order=4)]
public int Color {get;set;}
[DataMember(Order=5)]
public double Quantity {get;set;}
[DataMember(Order=8)]
public int Version {get;set;}
[DataMember(Order=6)]
public int Material {get;set;}
[DataMember(Order=7)]
public int Warehouse {get;set;}
I'm trying to parse a xml file in an object
This is my xml file named Changelog.xml
<?xml version="1.0" encoding="utf-8" ?>
<Changelog>
<Releases>
<Release>
<Version>1507</Version>
<Date>22-11-2013</Date>
<Changes>
<Change>Change1</Change>
<Change>Change2</Change>
<Change>Change3</Change>
<Change>Change4</Change>
</Changes>
</Release>
<Release>
<Version>1506</Version>
<Date>20-11-2013</Date>
<Changes>
<Change>Change1</Change>
</Changes>
</Release>
</Releases>
</Changelog>
This is my Changelog object I want to cast the xml to
[XmlRoot()]
public class Changelog
{
private List<Release> releases;
public List<Release> Releases
{
get { return releases; }
set { releases = value; }
}
}
public class Release
{
private string version;
private string date;
private List<ChangeItem> changes;
[XmlElement]
public string Version
{
get { return version; }
set { version = value; }
}
[XmlElement]
public string Date
{
get { return date; }
set { date = value; }
}
[XmlElement]
public List<ChangeItem> Changes
{
get { return changes; }
set { changes = value; }
}
}
public class ChangeItem
{
private string change;
[XmlElement]
public string Change
{
get { return change; }
set { change = value; }
}
}
Here I read the file
XmlSerializer serializer = new XmlSerializer(typeof(Changelog));
Changelog changelog = (Changelog)serializer.Deserialize(new StreamReader(#"changelog.xml"));
Releases = changelog.Releases;
foreach (Release release in Releases)
{
string version = release.Version;
string date = release.Date;
List<ChangeItem> changes = release.Changes; // Has only 1 item
}
The problem is that there is only 1 object in the Changes list, altough I expect 4 for the 1507 release.
What am I doing wrong?
You have ChangeItem.Change property decorated with an XmlElement attribute. This means it becomes another element.
Thus the xml would need to look different.
To make it work, mark the property with the [XmlText] attribute.
Also, your Release.Changes needed to be decorated with a XmlArray and a XmlArrayItem attribute.
[XmlRoot]
public class Changelog
{
private List releases;
public List Releases
{
get { return releases; }
set { releases = value; }
}
}
public class Release
{
private string version;
private string date;
private List changes;
[XmlElement]
public string Version
{
get { return version; }
set { version = value; }
}
[XmlElement]
public string Date
{
get { return date; }
set { date = value; }
}
[XmlArray("Changes")]
[XmlArrayItem("Change")]
public List Changes
{
get { return changes; }
set { changes = value; }
}
}
public class ChangeItem
{
private string change;
[XmlText]
public string Change
{
get { return change; }
set { change = value; }
}
}
I marked in bold what my changes were.
change
[XmlElement]
public List<ChangeItem> Changes
{
get { return changes; }
set { changes = value; }
}
to
[XmlArray("Changes")]
public List<ChangeItem> Changes
{
get { return changes; }
set { changes = value; }
}
I am using WCF Test Client (WcfTestClient.exe) for testing one of my wcf services.
I have a message contract which has a list of DataContracts as :
My message contract is as follows :
[MessageContract]
public class UpdateInvoiceStatusesRequest
{
private List<InvoiceStatusHistory> _invoiceStatusHistory;
[MessageBodyMember(Order = 0)]
public List<InvoiceStatusHistory> InvoiceStatusHistory
{
get { return _invoiceStatusHistory; }
set { _invoiceStatusHistory = value; }
}
}
and my data contract is :
[DataContract]
public class InvoiceStatusHistory
{
private int _invoiceId;
private int _status;
private string _comment;
private string _timeStamp;
[DataMember]
public int InvoiceId
{
get { return _invoiceId; }
set { _invoiceId = value; }
}
[DataMember]
public string Comment
{
get { return _comment; }
set { _comment= value; }
}
[DataMember]
public int Status
{
get { return _status; }
set { _status = value; }
}
[DataMember]
public string TimeStamp
{
get { return _timeStamp; }
set { _timeStamp = value; }
}
}
when i am using WcfTestClient.exe to test the service with UpdateInvoiceStatusesRequest message contract it shows the value of InvoiceStatusHistory as length = 0, now i don't know how can i add the objects of InvoiceStatusHistory in List<InvoiceStatusHistory> ?
Does anyone has any idea about it, please help me?
Type length=1 in the box. A + sign will appear next to the request parameter name. Click on it, then on the [0] node which indicates the first element in the array and set its values as usual.
I've got class in WCF. Inside this class - there are 2 classes, 1 interface and several variables. It adds as service reference without errors.
[ServiceContract(Namespace = "")]
[SilverlightFaultBehavior]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class XmlService
{
private string filename;
private XmlTextReader xmlreader;
List<IWeather> returner=new List<IWeather>();
[OperationContract]
public void DoWork()
{
// Add your operation implementation here
return;
}
interface IWeather
{
string GetCondition { get; set; }
DateTime GetDate { get; set; }
}
public class Current_Weather:IWeather
{
private string condition, humidity, wind_condition;
private int temp_f, temp_c;
private DateTime day;
public string GetCondition
{
get { return condition; }
set { condition = value; }
}
public string GetHumidity
{
get { return humidity; }
set { humidity = value; }
}
public string GetWindCondition
{
get { return wind_condition; }
set { wind_condition = value; }
}
public int TEMP_F
{
get { return temp_f; }
set { temp_f = value; }
}
public int TEMP_C
{
get { return temp_c; }
set { temp_c = value; }
}
public DateTime GetDate
{
get { return day; }
set { day = value; }
}
}
public class Forecast_Weather:IWeather
{
public string condition;
public int lowT, highT;
public DateTime day;
public string GetCondition
{
get { return condition; }
set { condition = value; }
}
public int GetLowT
{
get { return lowT; }
set { lowT = value; }
}
public int HighT
{
get { return highT; }
set { highT = value; }
}
public DateTime GetDate
{
get { return day; }
set { day = value; }
}
}
}
Should I add contracts to variables,interface IWeather, for inner classes and its methods and variables?
If you want them serialzied and visible on the client they need to be marked with contract attributes.
Internal classes aren't really a good practice, instead put all your operations in one interface marked up as a service contract, then all your data contracts in their own class libraries so you can reference that assemply frmo your client. This facilitates writing your own proxies and other good habits.
Your internal classes will not be exposed to callers of your service, since your service doesn't use them either as parameters or as return values.
I've had a class which looked like
public class MyClass
{
public string EmployerName;
public string EmployerSurname;
public string EmploeeName;
public string EmploeeSurname;
}
I've refactored the code above to this:
public class MyClass
{
public MyClass()
{
Employer = new PersonInfo();
Emploee = new PersonInfo();
}
public class PersonInfo
{
public string Name;
public string Surname;
}
public PersonInfo Emploee;
public PersonInfo Employer;
[Obsolete]
public string EmploeeName
{
get
{
return Emploee.Name;
}
set
{
Emploee.Name = value;
}
}
[Obsolete]
public string EmploeeSurname
{
get
{
return Emploee.Surname;
}
set
{
Emploee.Surname= value;
}
}
[Obsolete]
public string EmployerName
{
get
{
return Employer.Name;
}
set
{
Employer.Name = value;
}
}
[Obsolete]
public string EmployerSurname
{
get
{
return Employer.Surname;
}
set
{
Employer.Surname = value;
}
}
Problem is, that when deserializing XMLs, which were serialized from old class version, I hoped that the new properties would work, and fields of the inner objects would be filled, but they don't.
Any ideas how, besides implementing IXmlSerializable, I could modify the new class to support both new and old versions of XMLs? Or maybe IXmlSerializable is the only way?
Do you only want to support the old ones for deserialization? if so, you could have:
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public string EmploeeName {
get { return Emploee.Name; }
set { Emploee.Name = value; }
}
public bool ShouldSerializeEmploeeName() { return false;}
The bool method tells XmlSerializer never to write this, but it will still be read. [Browsable] tells it not to appear in things like DataGridView, and [EditorBrowsable] tells it not to appear in intellisense (only applies to code referencing the dll, not the project, nor code in the same project).