【问题标题】:WCF DataContract with readonly properties具有只读属性的 WCF DataContract
【发布时间】:2011-01-30 11:54:45
【问题描述】:

我正在尝试从 WCF 中的服务方法返回复杂类型。我正在使用 C# 和 .NET 4。这种复杂类型是不变的(与 .net 字符串相同)。此外,服务只返回它,从不接收它作为参数。

如果我尝试仅在属性上定义 getter,则会出现运行时错误。我猜这是因为没有设置器会导致序列化失败。不过,我认为这种类型应该是不变的。

例子:

[DataContract]
class A 
{
   [DataMember]
   int ReadOnlyProperty {get; private set;}
}

由于序列化问题,服务加载失败。

有没有办法在 WCF DataContract 上创建只读属性?也许通过更换序列化程序?如果是这样,怎么做?如果没有,您对这个问题有何建议?

谢谢,
阿萨夫

【问题讨论】:

  • 您可以使用只读字段(非属性)并在类的构造中初始化它们。另外...,可能重复:stackoverflow.com/q/1873741/945456
  • 随着转向不可变类和 C#-6.0 对自动实现的 get-only 属性的支持,这一点在今天变得更加重要。

标签: .net wcf .net-4.0 datacontract


【解决方案1】:

[DataMember] 放在支持字段上,您将不需要 setter。

【讨论】:

  • 但它不会是只读的,也不会表示它应该是只读的。
  • 它永远不会是只读的。通过网络传输的数据合同只是一个 XML。你不能使一段 XML 只读。你不能电线另一端的人不改变它的价值。它只是不能那样工作。
  • 如果将值传递给服务,您可以简单地忽略它吗?只读是指服务只返回它吗?
  • @Bryan:是的。服务只返回它,我想准确地表达出来。
【解决方案2】:

公开您的 setter 以满足序列化程序的要求,但不要对 setter 执行任何操作。不是“纯粹主义者”,但可以做到

public string MyProperty 
{
    get {
        return this._myProperty
    }
    set {}
}

【讨论】:

    【解决方案3】:

    DataMember 字段不能是只读的,因为 wcf 不会按原样序列化对象,并且每次反序列化开始时都会使用默认构造函数创建新的对象实例。 Dispatcher 在反序列化后使用 setter 设置字段值。

    但是所有的大写都可能是一个大错误:)

    要使它们真正只读,请创建服务器逻辑,验证此字段值。

    【讨论】:

    【解决方案4】:

    您不能将属性设置为只读,但是您可以通过将字段设置为合同的一部分而不是属性来接近只读:

    [DataContract]
    public class A 
    {
       public class A(){}
       public class A(int readonlyproperty){ _readonlyproperty = readonlyproperty}
    
       [DataMember(Name = "ReadOnlyProperty")]
       internal int _readonlyproperty;
    
       public int ReadOnlyProperty {
          get {return _readonlyproperty;}
          private set {_readonlyproperty = value;}
    }
    

    接下来让您的内部结构在 wcf 中可访问:

    [assembly: InternalsVisibleTo("System.Runtime.Serialization")]
    

    一些关于如何使用它的示例:wcf-and-datacontract-serialization-internals-and-tips

    【讨论】:

      【解决方案5】:

      正如其他人所说,WCF 需要 getter 和 setter。 话虽如此,我带着同样的问题来到这里,答案让我问为什么我需要一个只读属性。如果您使用 MVVM 模式,则服务返回的类是模型,因此不应直接由 UI 公开。您可以轻松地将 ViewModel 设为只读。或者,您可以使用非面向 UI 的外观类。

      【讨论】:

        【解决方案6】:

        实际上,您可以使只读字段可序列化。构建DataContractSerializer时,需要将DataContractSerializerSettings的'SerializeReadOnlyTypes'属性设置为'True',如下:

        var xmlSerializer = new DataContractSerializer(typeof(yourTypeHere),  new DataContractSerializerSettings {SerializeReadOnlyTypes=true});
        

        在此处查看 MSDN 说明和详细信息:https://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractserializersettings(v=vs.110).aspx

        【讨论】:

          【解决方案7】:

          WCF 需要能够序列化/反序列化属性,而私有属性则无法做到这一点。拥有只读属性(在复杂类型中):

          • 将类装饰为 [DataContract(IsReference = true)]
          • 将每个/属性装饰为 [DataMember]
          • 公开获取,内部设置
              [DataContract(IsReference = true)]
              public class Format : ValueObject<Format>
              {
                  [DataMember]
                  public int Height { get; internal set; }
              }
          

          【讨论】:

            【解决方案8】:

            您是否尝试过将 setter 设为私有?

            类似:

            public string MyProperty
            {
            get;
            private set;
            }
            

            【讨论】:

            • 是的。这正是我的问题。
            • 所以这解决了?或者这就是你正在尝试的?
            • 它不起作用。如果我将 MyProperty 设为 [DataMember],据我所知,我会从序列化中得到一个运行时错误。它会在服务加载后立即发生 - 即使在客户端操作期间也是如此。
            • @AsafR:正确,看来您必须为所有字段设置一个 get/set 才能使序列化/反序列化工作。从我读过的所有内容中,我认为没有办法解决这个问题:(
            • 如果你想把你的结论放在上面的答案中,我很乐意让它成为公认的答案。
            猜你喜欢
            • 1970-01-01
            • 2011-02-04
            • 2013-08-31
            • 2012-12-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-08-20
            • 1970-01-01
            相关资源
            最近更新 更多