XML Serialization in .NET - what's wrong with this - c#

I have xml like this:
<?xml version="1.0" encoding="utf-8"?>
<session xmlns="http://winscp.net/schema/session/1.0" name="blah#blah.com" start="2011-10-03T15:09:30.481Z">
<ls>
<destination value="/incoming/monthly" />
<files>
<file>
<filename value="2.txt" />
<type value="D" />
<modification value="2011-09-14T12:58:26.000Z" />
<permissions value="rwxr-xr-x" />
</file>
<file>
<filename value="3.txt" />
<type value="D" />
<modification value="2011-01-03T22:04:55.000Z" />
<permissions value="rwxr-xr-x" />
</file>
</files>
<result success="true" />
</ls>
</session>
My representation of the following is:
<XmlRoot("session", Namespace:="http://winscp.net/schema/session/1.0")>
Class XMLSession
<XmlElement("ls/files/file")>
Public Property FileList As New List(Of XMLFile)
End Class
<XmlType("file")>
Class XMLFile
<XmlElement("filename")>
Public Property FileName As XMLValueAttribute
<XmlElement("type")>
Public Property TypeName As XMLValueAttribute
<XmlElement("permissions")>
Public Property Permissions As XMLValueAttribute
<XmlElement("modification")>
Public Property ModificationDate As XMLValueAttribute
End Class
Class XMLValueAttribute
<XmlAttribute("value")>
Public Property Value As String
End Class
Why is XMLSession.FileList.Count always 0. I hypothesize it has something to do with the declaration above it but I am not sure what is wrong with it. Maybe it can't accept a path, if not, how can I do it?

You can't describe multiple levels of XML with a single XmlElementAttribute. You need classes for each level.

If you don't want to build the classes by hand, you can get the tools to do it for you:
Assuming your XML is saved in data.xml:
xsd.exe data.xml
This will give you data.xsd which defines the XML.
xsd.exe /l:VB /n:SomeNamespace /c data.xsd
This will give you a codefile data.vb with your types defined, which you can add to your project.
Problem with this one is that there's some kind of bug, described here, which throws an error when you create a serializer around this new type. So you just need one manual tweak on the generated code, changing:
<XmlArrayItemAttribute("file", GetType(sessionLSFilesFile), IsNullable:=False)> _
'To
<XmlArrayItemAttribute("file", GetType(sessionLSFilesFile()), IsNullable:=False)> _

Related

Obfuscar - skip obfuscation of anonymous types

I'm using the open source obfuscation software "Obfuscar". Is there a way to configure it to not obfuscate the property names in my anonymous types?
I'm using RestSharp to send HTTP requests, and my Json body content is an anonymous type.
request.AddJsonBody(new {
data = new {
type = "attachments",
attributes = new {
name = "foo"
}
}
});
I would like it to NOT rename those properties like "data", "type" etc in the anonymous type, because renaming them affects the Json string that it gets serialized to.
In github obfuscar issues i found this answer and it worked for me
You need to create the node in Obfuscar xml configuration file:
<SkipType name="*AnonymousType*" skipProperties="true" skipMethods="true" skipFields="true" skipEvents="true" skipStringHiding="true" />
Example of full xml configuration file:
<?xml version="1.0" encoding="utf-8"?>
<Obfuscator>
<Var name="OutPath" value="C:\TMP" />
<AssemblySearchPath path="C:\Users\user\Documents\Projects\MyProject\bin\Release\net6.0" />
<AssemblySearchPath path="C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.0" />
<Module file="C:\Users\user\Documents\Projects\MyProject\bin\Release\net6.0\MyProject.dll">
<SkipType name="*AnonymousType*" skipProperties="true" skipMethods="true" skipFields="true" skipEvents="true" />
</Module>
<Var name="KeepPublicApi" value="false" />
<Var name="HidePrivateApi" value="true" />
</Obfuscator>
Next, you need to start obfuscar.exe -s "path_to_xml_configuration_file"
Also see the section in the Obfuscar documentation
https://docs.obfuscar.com/getting-started/configuration#exclusion-rules-by-configuration

What level of complexity can a custom ConfigSection XML contain while using built-in Section Handler classes?

This example on MSDN shows how to implement a simple dictionary inside a custom App.config section:
https://msdn.microsoft.com/en-us/library/aa719887(v=vs.71).aspx
The XML looks like this, and it employs SingleTagSectionHandler:
<sampleSection setting1="Value1" setting2="value two"
setting3="third value" />
Is this the most complicated my custom XML section can be before I have to write my own config section class? Because I wish to have a section which is slightly more complex e.g:
<mySection>
<mappings>
<mapping name="A" val1="12" val2="32"/>
<mapping name="B" val1="2" val2="2"/>
</mappings>
<add name="URL" value="http://..."/>
</mySection>
Or something along those lines at least, the exact structure isn't rigid.
How far can I push the built-in section handlers? I couldn't see a good tutorial on what is actually provided in system.configuration.

Irregular xml file processing

I need to process information from an XML-like file. Does anyone know some library/inbuild class (preferably c#) which might be useful to deal with that type of document (with not much effort) ?
Below is a piece of the XML :
<query>
<type id="excel" />
<ids>
<id value="47" />
<id value="2067" />
<id value="247" />
<id value="329" />
<id value="19" />
<id value="485" />
<id value="148" />
<id value="203" />
<id value="219" />
<id value="1503" />
<id value="7318" />
</ids>
<period value="Monthly" />
<start month="01" year="1990" />
<end month="12" year="2015" />
</query>
This appears to be a perfectly valid XML file.
There are System.Xml.XmlDocument class and System.Xml.Linq.XDocument class, both deal with parsing (and constructing) XML.
You can also build a class model and then use XmlSerializer class to deserialize the xml into a class hierarchical model instance.
Welcome to StackOverflow :D
There are 2 tools that should help you in dealing with it :
XSD.EXE will generate a schema and classes that you can add to your project
XSD2Code will generate classes from a schema as well as Serialize/Deserialize methods
Suggestion :
Use XSD.EXE to generate your schema then use XSD2Code to generate classes from that schema.
Both tools are free,
The first one you access it through the Developer Command Line :
xsd file.xml
The second one is a Visual Studio add-in : (tutorial on their site)
Do not forget to accept the answer if you are satisfied with it or ask for more details by editing your question.

How to correctly serialize class derived from collection using DataContracts

In C# and .NET 4.5 I'm in the process of implementing XML generation/parsing by means of DataContract serialization which appears extremely effective.
I have, however, run into a number of problems in a couple of situations I hope somebody can help me with.
The relevant classes are the following 5 (plus a number of embedded objects):
[DataContract]
public abstract class ItemList<T> : List<T>, IList
{
.....
}
[DataContract]
public class CashFlowList : ItemList<CashFlow>
{
.....
}
[DataContract]
public class CashFlow : ItemList<CashFlowPayment>
{
.....
}
[DataContract]
public class CashFlowPayment : ListItem, IDataImportExport
{
.....
}
[DataContract]
public abstract class ListItem : System.IComparable, IList
{
.....
}
When using the DataContractSerializer (on the CashFlowList type), the resulting XML looks like this:
<CashFlowList xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/FinancialData">
<_items>
<CashFlow>
<_items>
<CashFlowPayment>
<ID>-1</ID>
<ProbDist xmlns:d6p1="http://schemas.datacontract.org/2004/07/ProbabilityDistributions" i:nil="true" />
<UseProbabilityDistribution>true</UseProbabilityDistribution>
<ValidFrom>0001-01-01T00:00:00</ValidFrom>
<ValidThrough>9999-12-31T23:59:59.9999999</ValidThrough>
<Amount>4500</Amount>
<Ccy i:nil="true" />
<Date>2012-02-03T00:00:00</Date>
<DaysFromStartDate>-1</DaysFromStartDate>
</CashFlowPayment>
<CashFlowPayment>
<ID>-1</ID>
<ProbDist xmlns:d6p1="http://schemas.datacontract.org/2004/07/ProbabilityDistributions" i:nil="true" />
<UseProbabilityDistribution>true</UseProbabilityDistribution>
<ValidFrom>0001-01-01T00:00:00</ValidFrom>
<ValidThrough>9999-12-31T23:59:59.9999999</ValidThrough>
<Amount>-30000</Amount>
<Ccy i:nil="true" />
<Date>2013-04-10T00:00:00+02:00</Date>
<DaysFromStartDate>465</DaysFromStartDate>
<DaysUntilEndDate>-1</DaysUntilEndDate>
<IsPerpetual>false</IsPerpetual>
<PaymentType>Unknown</PaymentType>
<Schedule xmlns:d6p1="http://schemas.datacontract.org/2004/07/Schedules" i:nil="true" />
</CashFlowPayment>
<CashFlowPayment i:nil="true" />
<CashFlowPayment i:nil="true" />
</_items>
<_size>2</_size>
<_version>3</_version>
<ID>-1</ID>
<Name></Name>
<ProbDist xmlns:d4p1="http://schemas.datacontract.org/2004/07/ProbabilityDistributions" i:nil="true" />
<UseProbability>false</UseProbability>
<ValidFrom>0001-01-01T00:00:00</ValidFrom>
<ValidThrough>9999-12-31T23:59:59.9999999</ValidThrough>
<BaseCCY></BaseCCY>
..............................
<StartDate>2012-05-09T00:00:00</StartDate>
<SumOfNegativePayments>-30000</SumOfNegativePayments>
<SumOfPositivePayments>4500</SumOfPositivePayments>
<ValueDate>0001-01-01T00:00:00</ValueDate>
<XMLCashFlowElementName i:nil="true" />
<XMLPaymentElementName i:nil="true" />
<XMLPaymentsElementName i:nil="true" />
</CashFlow>
<CashFlow i:nil="true" />
<CashFlow i:nil="true" />
<CashFlow i:nil="true" />
</_items>
<_size>1</_size>
<_version>1</_version>
<ID>-1</ID>
<Name></Name>
<ProbDist xmlns:d2p1="http://schemas.datacontract.org/2004/07/ProbabilityDistributions" i:nil="true" />
<UseProbability>false</UseProbability>
<ValidFrom>0001-01-01T00:00:00</ValidFrom>
<ValidThrough>9999-12-31T23:59:59.9999999</ValidThrough>
</CashFlowList>
The generated XML is correct - but has a number of quirks: first of all the <_items> elements which I guess are required for the serializer to manage the output.
Secondly, you will notice that each collection - within the <_items> elements always has a minimum of 4 child elements - for example, adding another CashFlow to the
outer will result in only 2 elements - why, and is there a way of getting around that ?
Replacing one or more [DataContract] attributes with [CollectionDataContract] - regardless of what properties are set within the attributes - will produce
grammatically correct XML output as expected, but now - for each class having the [CollectionDataContract] attribute - only the collection items are output - and not the regular
properties within the class. I.e. an example would be:
<CashFlowList xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/FinancialData">
<CashFlow>
<CashFlowPayment>
....
</CashFlowPayment>
</CashFlow>
</CashFlowList>
In the example above the following elements (in the outer CashFlowList object) have been ignored:
<ID>-1</ID>
<Name></Name>
<ProbDist xmlns:d2p1="http://schemas.datacontract.org/2004/07/ProbabilityDistributions" i:nil="true" />
<UseProbability>false</UseProbability>
<ValidFrom>0001-01-01T00:00:00</ValidFrom>
<ValidThrough>9999-12-31T23:59:59.9999999</ValidThrough>
So my question is whether this is by design and is unavoidable - i.e. can you output a class derived from a collection and include additional properties in the output
when using the [CollectionDataContract] attribute ?
Interestingly, if [CollectionDataContract] attributes are used, you can generate/retrieve the corresponding XSD using the XsdDataContractExporter class without
problems (except that the XML is incomplete due to the missing properties). When using [DataContract] attributes, however, the XSD cannot be generated (fails in
the CanExport method), but the XML is correct and complete, but not particularly legible.
I would therefore really appreciate any insights and/or thoughts on this.
Best regards and thanks,
Michael

How do I add a namespace to only ref elements in C#?

I have an XElement which contains the content that I want. However, I want to add a namespace prefix to only the ref elements. Is this possible in C#?
For example, the original XML looks like this:
<Root>
<Element1 />
<Element2 />
<Element3>
<Element3_Child1 />
<Element3_Child2 />
</Element3>
<Element4 />
<Element5>
<Element5_Child1>
<Element5_Child1_Child51 />
</Element5_Child1>
</Element5>
</Root>
I want to add a namespace prefix, so that the XML looks as below
<Root>
<Element1 />
<Element2 />
<ns:Element3>
<Element3_Child1 />
<Element3_Child2 />
</Element3>
<Element4 />
<ns:Element5>
<ns:Element5_Child1>
<Element5_Child1_Child51 />
</Element5_Child1>
</Element5>
</Root>
You can do as stated here : http://www.w3schools.com/xml/xml_namespaces.asp
<root
xmlns:foo="http://www.example.org/foo"
xmlns:bar="http://www.example.org/bar">
However, I'm pretty sure you'll need a valid URI and that you can't "fake" one. Otherwise, the namespace will be invalid. But you can test and let us know.

Categories

Resources