IgnoreDataMember doesn't work for me

1,648 views
Skip to first unread message

Brannon

unread,
Aug 20, 2012, 7:02:28 PM8/20/12
to servic...@googlegroups.com
I was surprised today to see that ServiceStack returned every property on my object. This was after I carefully marked all my objects with DataContract and DataMember attributes. I expected that only those properties with a DataMember attribute would be returned. After reading around it seems that ServiceStack is not an opt-in serializer -- it's an opt-out. I went back and added IgnoreDataMember attributes to all the other properties. No change. I then removed the DataContract/DataMember such that only IgnoreDataMember attributes remained. No Change. It still brought everything back. What am I doing wrong here?

PS. In the current code, the MarkdownPlugin fails to load in my codebase with the FileNotFoundException: "Virtual file not found".

Demis Bellot

unread,
Aug 20, 2012, 7:18:54 PM8/20/12
to servic...@googlegroups.com
Submit a failing tests if you think you've found a bug and we'll take a look at it, i.e. these tests show [IgnoreDataMember] working:

Once you decorate your DTO with [DataContract] it becomes opt-in. If you only use  [IgnoreDataMember] its opt-out.

Note: don't rely on live repo it's not guaranteed to be in a working state - e.g. I'm still working on sharing the the same VirtualFS between the new MVC Razor / Markdown Razor view engines.


On Mon, Aug 20, 2012 at 7:02 PM, Brannon <notac...@gmail.com> wrote:
I was surprised today to see that ServiceStack returned every property on my object. This was after I carefully marked all my objects with DataContract and DataMember attributes. I expected that only those properties with a DataMember attribute would be returned. After reading around it seems that ServiceStack is not an opt-in serializer -- it's an opt-out. I went back and added IgnoreDataMember attributes to all the other properties. No change. I then removed the DataContract/DataMember such that only IgnoreDataMember attributes remained. No Change. It still brought everything back. What am I doing wrong here?

PS. In the current code, the MarkdownPlugin fails to load in my codebase with the FileNotFoundException: "Virtual file not found".



Brannon

unread,
Aug 21, 2012, 11:58:56 AM8/21/12
to servic...@googlegroups.com
Following your advice I wrote some tests. It ends up that when you put the classes in a list of type baseclass, the serializer uses the attributes of the base class/interface instead. That's a little weird. I don't believe the standard .Net serializers work that way. This test fails on the very last line:

interface ITest {
string One { get; set; }
string Two { get; set; }
}

class Test1: ITest
{
public string One { get; set; }

[IgnoreDataMember]
public string Two { get; set; }
}

[DataContract]
class Test2 : ITest
{
[DataMember]
public string One { get; set; }

public string Two { get; set; }
}

[Test]
public void ContractAttribsWork()
{
var c1 = new Test1 { One = "1", Two = "2" };
var c2 = new Test2 { One = "1", Two = "2" };

var c1s = JsonSerializer.SerializeToString(c1);
Assert.IsTrue(c1s.Contains("One"));
Assert.IsFalse(c1s.Contains("Two"));

var c2s = JsonSerializer.SerializeToString(c2);
Assert.IsTrue(c2s.Contains("One"));
Assert.IsFalse(c2s.Contains("Two"));

var list = new List<ITest> {c1, c2};
var c3s = JsonSerializer.SerializeToString(list);
Assert.IsTrue(c3s.Contains("One"));
Assert.IsFalse(c3s.Contains("Two"));
}

Brannon

unread,
Aug 21, 2012, 12:10:05 PM8/21/12
to servic...@googlegroups.com
Yikes! I can't make it work. Unfortunately, when serializing a list of type base interface, only fields on that interface are serialized. I have some fields on (some but not all) inheritors that also need to be serialized. And the DataContract attribute cannot be applied to interfaces so I'm left with the IgnoreDataMember attribute at the interface level. That seems to work, but I really need my other not-ignored fields on the inheritor.

Brannon

unread,
Aug 21, 2012, 12:31:50 PM8/21/12
to servic...@googlegroups.com
I did come up with a workaround. I put the properties on the interface even though they don't apply to all inheritors. Then, inside the inheritors, I implemented them explicitly. I was able to return null or a sensible constant for each.

Demis Bellot

unread,
Aug 21, 2012, 12:34:44 PM8/21/12
to servic...@googlegroups.com
Why are you using Interfaces on DTOs?


On Tue, Aug 21, 2012 at 12:31 PM, Brannon <notac...@gmail.com> wrote:
I did come up with a workaround. I put the properties on the interface even though they don't apply to all inheritors. Then, inside the inheritors, I implemented them explicitly. I was able to return null or a sensible constant for each.



Brannon

unread,
Aug 21, 2012, 12:46:50 PM8/21/12
to servic...@googlegroups.com
Why are you using Interfaces on DTOs?


Here's my DTO definitions for returning geometric shapes. I considered returning the shapes as their own DTO for an endpoint "map/shapes" but I would still have to return a list of shapes for a single query. Please tell me what changes you suggest.

[DataContract]
internal class MapDtoResponse
{
[DataMember]
public ResponseStatus ResponseStatus { get; set; } //Automatic exception handling

[DataMember]
public MapLayerModel[] Layers { get; set; }
}

[DataContract]
internal class MapLayerModel
{
[DataMember]
public string Name { get; set; }

[DataMember]
public bool IsVisible { get; set; }
[DataMember]
public List<ShapeModel> Shapes { get; set; }
}

[DataContract]
[KnownType(typeof(ArcSegment))]
[KnownType(typeof(LineSegment))]
internal class ShapeModel
{
[DataMember]
public Guid UniqueId { get; set; }

[DataMember]
public string Name { get; set; }

[DataMember]
public bool IsVisible { get; set; }

[DataMember]
public bool IsObstacle { get; set; }

[DataMember]
public bool IsFilled { get; set; }

[DataMember]
public List<ISegment> Segments { get; set; }
}

 

Demis Bellot

unread,
Aug 21, 2012, 12:54:57 PM8/21/12
to servic...@googlegroups.com
Change all DTOs to public, Remove all traces of interfaces, and have flatten the DTOs (add a  ShapeType field if you need to distinguish them or have a different collection per ShapeType).
Normal POCOs (i.e. without inheritance) avoids requiring the serializer-specific [KnownType] types.

Interfaces / Inheritance is generally bad form to have on DTOs, I touch on why a bit here:
Reply all
Reply to author
Forward
0 new messages