Dynamically ignore data items from serialization

We have an existing WCF service that uses several DataContracts. We want to change device-based serialization so that when accessing from mobile devices, the service should only serialize some important data members (not all)

We have 2 options here.

  • Create separate operations and data contracts for different device types
  • A mess with the actual XML serialization and the suppression of creating unnecessary device-based elements

We don’t want to go with the first option, as it introduces a lot of redundant code problems in the future

Small studies have shown that we need to use IXmlSerializable and override the readXML () and writeXML () methods. But at the same time, I saw that DataContract and IXmlSerializable should not be used together

Any example related to actual serialization is welcome.

[DataContract] public class TokenMessage { string tokenValue; string extraValue; [DataMember] public string Token { get { return tokenValue; } set { tokenValue = value; } } [DataMember] public string Extra { get { return extraValue; } set { extraValue = value; } } } 

Now, when I access a service that returns a typical TokenMessage data contract from a mobile device, I don’t want the “Extra” data member to be serialized, i.e. when I provide another argument to the operation contract, it should be able to serialize some / all data elements (depending on the action)

PS: For now, please ignore the device discovery part. Let's say we have an argument in an operation contract that helps us identify the device

+8
c # serialization wcf
source share
4 answers

I'm not sure some answer option @Pranav Singh is not the best design, but that is not your question ...

As you mentioned in the comments, attributes in .NET are static in design. This means that dynamically adding / removing [DataMember] not a good option. Maybe. There are options such as using Reflection.Emit to recreate an instance with metadata changes (see All Answers on Can I add dynamic attributes in C #? ), But all these routes are complicated.

I see two reasonable options:

1) Add the IParameterInspector for the service . In the AfterCall () method, you can check and change the parameters returned to the client before they are serialized. There is some work to use reflection to dynamically determine the types of parameters and set their values, but this is not difficult. This is the best design that allows you to reuse behavior in many contracts or services. Carlos Figueira's blog is the best source for examples of the WCF extension.

2) Use [OnSerializing] and [OnSerialized] . In [DataContract], you can temporarily change the properties returned by serialization. Events are actually meant to be initialized, and thus this solution is a bit hacked. This solution is also not thread safe. But it saves the code contained in the DataContract class, and quickly solves the problem (and I think you're looking fast).

Solution # 2: it looks something like this:

 [DataContract] public class TokenMessage { string tokenValue; string extraValue; bool enableExtraValue = true; [DataMember] public string Extra { get { if (enableExtraValue) return extraValue; return null; } set { extraValue = value; } } [OnSerializing()] internal void OnSerializingMethod(StreamingContext context) { enableExtraValue = false; } [OnSerialized()] internal void OnSerializedMethod(StreamingContext context) { enableExtraValue = true; } } 

Solution # 2 is a quick fix (which is exactly what I think you're looking for).

Solution No. 1 is the best design.

+3
source share

There is an approach, but I think that this will require an additional DataContract, but still there is no need for separate contracts for operations and data for different types of devices. This may be a classic implementation for run-time polymorphism. I just give an idea:

Let's say you have a generic DataContract, for example:

 [DataContract] [KnownType(typeof(Extra))] [KnownType(typeof(Extra2))] public class TokenMessage { string tokenValue; string extraValue; [DataMember] public string Token { get { return tokenValue; } set { tokenValue = value; } } } 

Other device-specific contracts can inherit TokenMessage as a base class, for example:

 [DataContract] public class Extra:TokenMessage { [DataMember] public string Extra { get ;set; } } [DataContract] public class Extra2:TokenMessage { [DataMember] public string Extra2 { get ;set; } } 

Now at run time, as you say, you know the argument in the operation contract, which helps us identify the device. Say, based on the type of device, you can create a base class with a derived class, for example:

 TokenMessage tm= new Extra(); 

OR

 TokenMessage tm= new Extra2(); 

So, at run time, you determine which device contract will be part of the genetic response.

Note. Adding KnownType will generate a separate xsd in wsdl for all known types in the base class, but preserves serialization for the data at run time, as this should depend on the actual inheritance chosen.

+1
source share
0
source share

In your model, add the property “ShouldSerializeYOUR_PROPERTY_NAME”, set it to false if you do not want the property to be serialized. More details here: http://msdn.microsoft.com/en-us/library/system.windows.dependencyobject.shouldserializeproperty(v=vs.110).aspx

-2
source share

All Articles