我有一个服务器端类,我通过[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 */ }
}
答案 0 :(得分:49)
您的“服务器端”课程不会“真正”提供给客户端。
这会发生什么:基于数据协定,客户端将从服务的XML模式创建一个新的单独类。它不能使用服务器端类本身!
它将从XML模式定义重新创建一个新类,但该模式不包含任何.NET特定的东西,如可见性或访问修饰符 - 毕竟它只是一个XML模式。将以这样的方式创建客户端类,使其在线路上具有相同的“足迹” - 例如它基本上序列化为相同的XML格式。
你无法通过标准的基于SOAP的服务“传输”关于该类的.NET特定技术 - 毕竟,您传递的所有内容都是序列化消息 - 没有课!
检查“SOA的四个原则”(由微软的Don Box定义):
参见第3点 - 服务共享模式和契约,不是类 - 您只共享数据契约的接口和XML模式 - 这就是全部 - 没有.NET类。
答案 1 :(得分:10)
将DataMember属性放在字段而不是属性上。
记住,WCF不知道封装。封装是一个OOP术语,而不是SOA术语。
尽管如此,请记住,对于使用您班级的人来说,该字段将是只读的 - 使用该服务的任何人都可以完全访问该字段。
答案 2 :(得分: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");
}
}
}
答案 3 :(得分:6)
有一种方法可以实现这一目标。但请注意,它直接违反了this answer中引用的以下原则:
“3.服务共享架构和合同,而不是类。”
如果此违规行为与您无关,那么您就是这样做的:
将服务和数据合同移动到单独的(可移植)类库中。 (让我们调用这个程序集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
)中引用合同程序集。这可能会导致解决方案中存在以下项目依赖性:
接下来,当您将服务引用添加到客户端项目时,请确保启用了“重用类型”选项,并确保您的合同程序集(SomeService.Contracts
)将包含在此:
瞧! Visual Studio不是从服务的WSDL模式生成新的Foo
类型,而是重用合同程序集中的不可变Foo
类型。
最后一个警告:你已经偏离了that other answer中引用的服务原则。但尽量不要误入歧途。您可能很想开始向数据协定类添加(业务)逻辑;别。他们应该尽可能地靠近愚蠢的数据传输对象(DTO)。
答案 4 :(得分:-3)
定义服务合同(接口)在使用类实现合同之前。