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

时间:2014-01-13 12:51:33

标签: c# .net wcf serialization

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

我们这里有2个选项

  1. 为不同类型的创建单独的操作和数据合同 设备
  2. 与实际的xml序列化混淆并抑制创建 基于设备的不必要元素
  3. 我们不想使用第一个选项,因为它在将来引入了许多冗余代码问题

    小型研究表明,我们需要使用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:现在请忽略设备检测部分。让我们假设我们在操作合同中有一个参数,这有助于我们识别设备

4 个答案:

答案 0 :(得分:3)

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

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

我看到两个合理的选择:

1)为服务实施IParameterInspector 。在AfterCall()方法中,您可以检查并更改在序列化之前返回到客户端的参数。有一些工作要使用反射来动态确定参数类型并设置它们的值,但它并不复杂。这是更好的设计,可以在许多合同或服务中重用行为。 Carlos Figueira's blog是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是更好的设计。

答案 1 :(得分: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作为基类继承,如:

[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();

OR

TokenMessage tm= new Extra2();

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

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

答案 2 :(得分:0)

答案 3 :(得分:-2)

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