WCF DataContract中的只读属性

20

我正在尝试从WCF服务方法中返回一个复杂类型。我使用的是C#和.NET 4。这个复杂类型应该是不变的(就像.NET字符串一样)。此外,该服务仅返回它,而不会将其作为参数接收。

如果我只定义属性的getter,那么我会得到运行时错误。我猜这是因为没有setter导致序列化失败。尽管如此,我认为这种类型应该是不变的。

例子:

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

由于序列化问题,该服务无法加载。

有没有办法在WCF DataContract上创建只读属性?也许通过替换序列化器来实现?如果可以,怎么做?如果不行,您对此有什么建议?

谢谢,
Asaf


你可以尝试在类的构造函数中使用只读字段(而非属性)进行初始化。另外,可能会出现重复问题,请查看:https://dev59.com/m3I-5IYBdhLWcg3wZ3fC。 - Jeff B
在不可变类和 C#-6.0 对自动实现的只读属性的支持下,这一点今天变得更加重要。 - binki
8个回答

16

[DataMember]放在后备字段上,您将不需要一个setter。


但它不会是只读的,并且也不会表达它应该是只读的。 - Asaf R
5
它永远不会变成只读。在传输过程中,数据契约只是一个XML格式的文件。你无法让这个XML变为只读。你也不能要求在接收端不改变它的值。它就是这样运作的。 - Krzysztof Kozmic
如果该值被传递到服务中,您可以简单地忽略它吗?您所说的“只读”是指该服务仅返回它吗? - Bryan Denny
@Bryan:是的。该服务只返回它,我想要准确地表达这一点。 - Asaf R

11

将你的 setter 设为 public 以满足序列化器,但是在 setter 中不做任何事情。不够“纯粹”但能完成任务。

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

5

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

但是所有上面的文本可能都是一个大错误 :)

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


1
在反序列化期间,它实际上不会调用默认构造函数。https://learn.microsoft.com/en-us/dotnet/api/system.runtime.serialization.datacontractserializer?view=netframework-4.7.2 - XWIKO
它也没有问题设置私有成员。 - Mathias Becher

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


1

0

WCF需要能够序列化/反序列化属性,但私有属性无法实现。要在复杂类型中拥有只读属性:

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

0

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


-2
你尝试过将设置器设为私有吗?
可以这样写:
```private set;```
public string MyProperty
{
get;
private set;
}

是的,那正是我的问题。 - Asaf R
这样就解决了吗?还是这正是你想要的? - Bryan Denny
它不起作用。如果我将MyProperty设置为[DataMember],我会得到一个运行时错误,据我最好的理解,这是由序列化引起的。它发生在服务加载时 - 即使不是在客户端操作期间。 - Asaf R
@AsafR:没错,似乎你必须为所有字段设置get/set才能实现序列化/反序列化。我认为从我读过的所有内容来看,这方面没有其他可行的方法 :( - Bryan Denny
2
如果您想在上面的答案中加入您的结论,我很乐意将其作为被接受的答案。 - Asaf R

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接