首页 文章

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

提问于
浏览
59

我有一个服务器端类,我通过[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; }
}

或者解决方案是使用[DataMember]作为字段 - (例如显示here)?尝试这样做,但它似乎并不关心该领域是readonly ..?

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

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

5 回答

  • 6

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

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

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

    您通过标准的基于SOAP的服务获得有关该类的.NET特定知识 - 毕竟,您传递的所有内容都是 serialized messages - 没有类!

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

    • 边界是明确的

    • 服务是自治的

    • 服务共享架构和 Contract ,而不是类

    • 兼容性基于政策

    请参阅第3点 - 服务共享架构和 Contract , not 类 - 您只共享数据 Contract 的接口和XML架构 - 这就是全部 - 没有.NET类 .

  • 10

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

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

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

  • 49

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

    不是真的'recommended',但这似乎是两个邪恶中较小的一个将 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");
            }
        }
    }
    
  • 7

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

    “3.服务共享架构和 Contract ,而不是类 . ”

    如果此违规行为与您无关,那么您就是这样做的:

    • 将服务和数据协定移动到单独的(可移植)类库中 . (让我们调用这个程序集 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] 应用于支持字段,而不是相应的只读属性 .

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

    screenshot highlighting the project dependencies in Solution Explorer

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

    screenshot highlighting the relevant service reference setting

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

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

  • -3

    定义服务 Contract (接口)在使用类实现 Contract 之前 .

相关问题