62

我有一个服务器端类,我通过 [DataContract] 在客户端提供它。此类有一个只读字段,我想通过属性使其可用。但是,我无法这样做,因为似乎不允许我在没有 get 和 set 的情况下添加 [DataMember] 属性。

那么 - 有没有办法在没有 setter 的情况下拥有 [DataMember] 属性?

[DataContract]
class SomeClass
{
    private readonly int _id; 

    public SomeClass() { .. }

    [DataMember]
    public int Id { get { return _id; } }        

    [DataMember]
    public string SomeString { get; set; }
}

或者解决方案将使用 [DataMember] 作为字段 - (如此处所示?也尝试过这样做,但它似乎并不关心该字段是只读的..?

编辑:是通过像这样破解它来制作只读属性的唯一方法吗?(不 - 我不想这样做......)

[DataMember]
public int Id
{
    get { return _id; }
    private set { /* NOOP */ }
}
4

5 回答 5

50

实际上,您的“服务器端”类不会对客户端“可用”。

发生的情况是这样的:基于数据契约,客户端将从服务的 XML 模式创建一个新的独立类。它本身不能使用服务器端类!

它将根据 XML 模式定义重新创建一个新类,但该模式不包含任何 .NET 特定的东西,如可见性或访问修饰符 - 毕竟它只是一个 XML 模式。客户端类将以这样一种方式创建,即它在线路上具有相同的“足迹”——例如,它基本上序列化为相同的 XML 格式。

不能通过标准的基于 SOAP 的服务“传输”有关该类的 .NET 特定知识 - 毕竟,您传递的只是序列化消息- 没有类!

检查“SOA 的四个原则”(由 Microsoft 的 Don Box 定义):

  1. 边界是明确的
  2. 服务是自治的
  3. 服务共享模式和契约,而不是类
  4. 兼容性基于策略

请参阅第 3 点 - 服务共享模式和合同,而不是类 - 您只共享数据合同的接口和 XML 模式 - 仅此而已 - 没有 .NET 类。

于 2009-12-09T13:21:42.347 回答
10

将 DataMember 属性放在字段而不是属性上。

请记住,WCF 不知道封装。封装是一个 OOP 术语,而不是 SOA 术语。

也就是说,请记住,该字段对于使用您的课程的人将是只读的 - 任何使用该服务的人都将拥有对该字段的完全访问权限。

于 2009-12-09T13:11:06.483 回答
8

有一种方法可以实现这一点。但请注意,它直接违反了此答案中引用的以下原则:

“3. 服务共享模式和契约,而不是类。”

如果此违规行为与您无关,您可以这样做:

  1. 将服务和数据契约移动到一个单独的(可移植的)类库中。(我们称这个程序集SomeService.Contracts为。)这是定义不可变[DataContract]类的方式:

    namespace SomeService.Contracts
    {
        [DataContract]
        public sealed class Foo
        {
            public Foo(int x)
            {
                this.x = x;
            }
    
            public int X
            {
                get
                {
                    return x;
                }
            }
    
            [DataMember]  // NB: applied to the backing field, not to the property!
            private readonly int x;
        }
    }
    

    请注意,[DataMember]它应用于支持字段,而不是对应的只读属性。

  2. 从您的服务应用程序项目(我称为 mine SomeService.Web)和您的客户端项目(我的称为SomeService.Client)中引用合同程序集。这可能会导致您的解决方案中出现以下项目依赖项:

    在解决方案资源管理器中突出显示项目依赖项的屏幕截图

  3. 接下来,当您将服务引用添加到您的客户端项目时,请确保启用“重用类型”选项,并确保您的合同程序集 ( SomeService.Contracts) 将包含在此:

    突出显示相关服务参考设置的屏幕截图

瞧!Visual Studio 不会从服务的 WSDL 架构中生成新Foo类型,而是会重用Foo合同程序集中的不可变类型。

最后一个警告:您已经偏离了另一个答案中引用的服务原则。但尽量不要再偏离。您可能很想开始向数据合约类添加(业务)逻辑;不。它们应该尽可能靠近哑数据传输对象 (DTO)。

于 2015-04-23T17:56:51.907 回答
7

我的服务层中的一个类中有一些属性,我想传递给 Silverlight。我不想创建一个全新的课程。

不是真的“推荐”,但这似乎是两个邪恶中较小的一个,将Total属性传递给silverlight(仅用于视觉数据绑定)。

public class PricingSummary
{
    public int TotalItemCount { get; set; } // doesnt ideally belong here but used by top bar when out of store area

    public decimal SubTotal { get; set; }
    public decimal? Taxes { get; set; }
    public decimal Discount { get; set; }
    public decimal? ShippingTotal { get; set; }
    public decimal Total
    {
        get
        {
            return + SubTotal
                   + (ShippingTotal ?? 0)
                   + (Taxes ?? 0)
                   - Discount;
        }
        set
        {
            throw new ApplicationException("Cannot be set");
        }
    }
}
于 2010-07-07T05:26:12.107 回答
-3

定义服务契约(接口) 在使用类实现契约之前。

于 2009-12-09T13:08:05.083 回答