WCF:没有设置公开只读DataMember属性?

sti*_*k81 59 .net wcf readonly datacontract datamember

我有一个服务器端类,我通过[DataContract]在客户端提供.这个类有一个readonly字段,我想通过一个属性提供.但是,我无法这样做,因为似乎我不允许在没有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; }
}
Run Code Online (Sandbox Code Playgroud)

或将溶液中使用[数据成员]作为字段- (例如像显示在这里)?尝试这样做,但它似乎并不关心该领域是readonly ..?

编辑:这是通过黑客攻击这样做的唯一方法来制作一个只读属性吗?(不 - 我不想这样做......)

[DataMember]
public int Id
{
    get { return _id; }
    private set { /* NOOP */ }
}
Run Code Online (Sandbox Code Playgroud)

mar*_*c_s 49

您的"服务器端"类不会"真正"提供给客户端.

会发生什么:根据数据协定,客户端将从服务的XML模式创建一个新的单独类.它本身不能使用服务器端类!

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

无法通过基于SOAP的标准服务"传输"有关该类的.NET特定知识 - 毕竟,您传递的所有内容都是序列化消息 - 没有类!

检查"SOA的四个原则"(由微软的Don Box定义):

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

请参阅第3点 - 服务共享模式和契约,而不是类 - 您只共享数据契约的接口和XML模式 - 这就是全部 - 没有.NET类.

  • 这个信息很好,但我不认为它直接回答了这个问题. (34认同)
  • 所有这些都说明了当前局势是多么荒谬.鉴于服务器端类仅用于生成合同,为什么需要setter?服务器上的一个实例可以在不使用它们的情况下将*正常*序列化到客户端,如果不是因为DataContractSerializer是不正常的.只有相反的情况会导致问题. (6认同)
  • 这很好地解释了它.谢谢你的澄清! (2认同)

Krz*_*mic 10

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

记住,WCF不知道封装.封装是OOP术语,而不是SOA术语.

也就是说,请记住,对于使用您班级的人来说,该字段将是只读的 - 使用该服务的任何人都可以完全访问该字段.

  • 没有.READONLY是一个C#术语,而不是SOA.您不能只读取XML的一部分 (4认同)

Sim*_*ver 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");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


sta*_*ica 7

有一种方法可以实现这一目标.但请注意,它直接违反了本答复中引用的以下原则:

"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;
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

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

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

    屏幕截图,在Solution Explorer中突出显示项目依赖项

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

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

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

最后一个警告:你已经偏离了其他答案中引用的服务原则.但尽量不要误入歧途.您可能很想开始向数据协定类添加(业务)逻辑; 别.他们应该尽可能地靠近哑巴数据传输对象(DTO).