简体   繁体   中英

Data contract serialization with complex types

I am using Data Contract serialization to serialize the following classes in XML:

[DataContract]
public partial class Foo
{
    [DataMember]
    public string MyString { get; set; }
    [DataMember]
    public int MyInt { get; set; }
    [DataMember]
    public Bar MyBar { get; set; }
}

[DataContract]
public class Bar
{
    public int BarId { get; set; }
    [DataMember]
    public string BarField { get; set; }
}

When I serialize it it generates XML like this:

<Foo>
    <MyString>My text</MyString>
    <MyInt>2</MyInt>
    <MyBar>
        <BarField>My bar field</BarField>
    </MyBar>
</Foo>

What I would like to do is have the MyBar field not appear as a complex type, but like this instead:

<Foo>
    <MyString>My text</MyString>
    <MyInt>2</MyInt>
    <MyBar>My bar field</MyBar>
</Foo>

I'm new to data contract serialization and haven't found any kind of tutorials that address my issue. I don't even know if it is possible or not but I figured I'd ask before I gave up and dealt with it the way it is or found a better solution.

By decorating data classes as DataContract , you are inherently setting the structure (Xml, Json etc) that the data will be represented as when it is serialized.

Can I suggest that you split the concerns of 'Business Entity' and 'Serialization Entity' out of your data classes, eg if Foo + Bar are your in memory or ORM representations of the data, then remove the [DataContract] s from them:

public partial class Foo
{
    public string MyString { get; set; }
    public int MyInt { get; set; }
    public Bar MyBar { get; set; }
}

public class Bar
{
    public string BarField { get; set; }
}

Then, provide a new class specifically for the serialized format, decorated with DataContract

[DataContract]
public partial class SerializableFoo
{
    [DataMember]
    public string MyString { get; set; }
    [DataMember]
    public int MyInt { get; set; }
    [DataMember]
    public string MyBar { get; set; }
}

And then provide a mapping function to map from the one to the other. LINQ is awesome for this kind of work, and if the classes have mostly the same property names, then AutoMapper can do a lot of the work for you

eg

var wireFoo = new SerializableFoo()
{
    MyString = foo.MyString,
    MyInt = foo.MyInt,
    MyBar = foo.Bar.BarField // Do the projection / flattening here
}
// Serialize wireFoo here, or return it from a WCF Service, etc.

You are defining it as a complex type... which means that it will come through as such. If you do not want that, then change your data contract for Foo to have Bar as a String, and not a complex type.

See basically, in XML terms, you define your class as a DataContract and your properties as DataMembers, you are creating your complex object, or an element that contains elements. In the case you presented, you would change your first data contract, so that it doesn't contain additional complex objects, only the data you want.

However, when applying OO design in these SOA situations, depending on what you are trying to accomplish, complex objects inside of other complex objects, can be easier to deal with, and even read, than a HUGE complex object full of properties.

To get your result, you would drop your Bar class and just have a string return in Foo.

[DataContract]
public partial class Foo
{
    [DataMember]
    public string MyString { get; set; }
    [DataMember]
    public int MyInt { get; set; }
    [DataMember]
    public string MyBar { get; set; }
}

EDIT: I guess I was not clear enough in the answer, which is NO you cannot get what you want and keep your complex types. Your XML is going to be structured based on your OO design.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM