动态忽略数据成员被序列化

我们有一个使用多个DataContracts的现有WCF服务。 我们想要根据设备修改序列化,这样当从移动设备访问时,服务应该只序列化一些重要的数据成员(不是全部)

我们这里有两个选择

  1. 为不同类型的设备创建单独的操作和数据协定
  2. 与实际的xml序列化混淆并抑制基于设备创建不必要的元素

我们不想使用第一个选项,因为它在将来引入了许多冗余代码问题

小型研究表明,我们需要使用IXmlSerializable并覆盖readXML()和writeXML()方法。 但与此同时,我已经看到DataContract和IXmlSerializable不应该一起使用的地方

任何搞乱实际序列化的例子都非常感谢。

[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; } } } 

现在,当我从移动设备访问返回典型TokenMessage数据协定的服务时,我不希望序列化“额外”数据成员,即当我向操作合同提供不同的参数时,它应该能够序列化部分/全部数据成员(取决于操作)

PS:现在请忽略设备检测部分。 让我们假设我们在操作合同中有一个参数,这有助于我们识别设备

我不相信@Pranav Singh的某些变体的答案不是更好的设计,但那不是你的问题……

正如您在评论中提到的,.NET中的属性是静态的。 这意味着动态添加/删除[DataMember]不是一个好选择。 有可能的。 有一些选项,比如使用Reflection.Emit来重新创建元数据更改的实例(请参阅可以在C#中动态添加Can属性的所有答案? )但所有这些路径都很复杂。

我看到两个合理的选择:

1) 为服务实现IParameterInspector 。 在AfterCall ()方法中,您可以检查并更改在序列化之前返回给客户端的参数。 有一些工作要使用reflection来动态确定参数类型并设置它们的值,但它并不复杂。 这是一种更好的设计,可以在许多合同或服务中重用行为。 Carlos Figueira的博客是WCF扩展示例的最佳来源。

2) 使用[OnSerializing][OnSerialized]事件。 在[DataContract]中,您可以临时更改序列化期间返回的属性。 事件实际上是为了启用初始化而设计的,因此这个解决方案有点像黑客攻击 。 此解决方案也不是线程安全的。 但它确实将代码保存到DataContract类并快速解决问题(我认为您正在寻找快速)。

解决方案#2可能看起来像:

 [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; } } 

解决方案#2是一个快速解决方案(我认为你正在寻找)。

解决方案#1是更好的设计。

有一种方法,但我认为这将需要生成额外的DataContract,但仍然不需要针对不同类型的设备进行单独的操作和数据合同。 它可以经典实现到运行时多态。 我只是在想:

假设你有一个通用的DataContract:

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

其他特定于设备的契约可以将TokenMessage作为基类inheritance,如:

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

现在在运行时,你说你知道操作合同中的一个参数,这有助于我们识别设备。 假设基于设备类型,您可以使用派生类实例化基类,如:

 TokenMessage tm= new Extra(); 

要么

 TokenMessage tm= new Extra2(); 

因此,在运行时,您将决定哪个设备合同将成为genric响应的一部分。

注意:添加KnownType将在wsdl中为基类中的所有已知类型生成单独的xsd,但在运行时保存数据的序列化,因为这应取决于所选的实际inheritance。

尝试使用IgnoreDataMemberAttribute

在您的模型中添加属性“ShouldSerializeYOUR_PROPERTY_NAME”,当您不希望序列化属性时将其设置为false。 在这里查看更多: http : //msdn.microsoft.com/en-us/library/system.windows.dependencyobject.shouldserializeproperty(v=vs.110).aspx