.net WCF:在未设置的情况下公开只读 DataMember 属性?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1873741/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WCF: Exposing readonly DataMember properties without set?
提问by stiank81
I have a server side class which I make available on the client side through a [DataContract]. This class has a readonly field which I'd like to make available through a property. However, I'm unable to do so because it doesn't seem that I'm allowed to add a [DataMember] property without having both get and set.
我有一个服务器端类,我通过 [DataContract] 在客户端提供它。这个类有一个只读字段,我想通过属性提供它。但是,我无法这样做,因为似乎不允许我在没有 get 和 set 的情况下添加 [DataMember] 属性。
So - is there a way to have a [DataMember] property without setter?
那么 - 有没有办法在没有 setter 的情况下拥有 [DataMember] 属性?
[DataContract]
class SomeClass
{
private readonly int _id;
public SomeClass() { .. }
[DataMember]
public int Id { get { return _id; } }
[DataMember]
public string SomeString { get; set; }
}
Or will the solution be use the [DataMember] as the field - (like e.g. shown here)? Tried doing this too, but it doesn't seem to care the field is readonly..?
或者解决方案将使用 [DataMember] 作为字段 - (例如此处所示)?也尝试过这样做,但它似乎并不关心该字段是否为只读..?
Edit: Is the only way to make a readonly property by hacking it like this? (no - I don't want to do this...)
编辑:是通过像这样破解它来制作只读属性的唯一方法吗?(不 - 我不想这样做......)
[DataMember]
public int Id
{
get { return _id; }
private set { /* NOOP */ }
}
采纳答案by marc_s
Your "server-side" class won't be "made available" to the client, really.
实际上,您的“服务器端”类不会对客户端“可用”。
What happens is this: based on the data contract, the client will create a new separate class from the XML schema of the service. It cannotuse the server-side class per se!
发生的事情是这样的:基于数据契约,客户端将从服务的 XML 模式创建一个新的独立类。它本身不能使用服务器端类!
It will re-create a new class from the XML schema definition, but that schema doesn't contain any of the .NET specific things like visibility or access modifiers - it's just a XML schema, after all. The client-side class will be created in such a way that it has the same "footprint" on the wire - e.g. it serializes into the same XML format, basically.
它将从 XML 模式定义重新创建一个新类,但该模式不包含任何 .NET 特定的东西,如可见性或访问修饰符——毕竟它只是一个 XML 模式。客户端类将以这样一种方式创建,即它在线路上具有相同的“足迹”——例如,它基本上序列化为相同的 XML 格式。
You cannot"transport" .NET specific know-how about the class through a standard SOAP-based service - after all, all you're passing around are serialized messages- no classes!
您无法通过标准的基于 SOAP 的服务“传输”有关该类的 .NET 特定知识 - 毕竟,您传递的只是序列化消息- 没有类!
Check the "Four tenets of SOA" (defined by Don Box of Microsoft):
查看“SOA 四大原则”(由微软的 Don Box 定义):
- Boundaries are explicit
- Services are autonomous
- Services share schema and contract, not class
- Compability is based upon policy
- 边界是明确的
- 服务是自主的
- 服务共享模式和契约,而不是类
- 兼容性基于策略
See point #3 - services share schema and contract, notclass - you only ever share the interface and XML schema for the data contract - that's all - no .NET classes.
参见第 3 点 - 服务共享架构和契约,而不是类 - 您只共享数据契约的接口和 XML 架构 - 仅此而已 - 没有 .NET 类。
回答by Krzysztof Kozmic
put DataMember attribute on a field not the property.
将 DataMember 属性放在字段而不是属性上。
Remember thought, that WCF does not know encapsulation. Encapsulation is a OOP term, not a SOA term.
请记住,WCF 不知道封装。封装是一个 OOP 术语,而不是 SOA 术语。
That said, remember that the field will be readonly for people using your class - anyone using the service will have full access to the field on their side.
也就是说,请记住该字段对于使用您的类的人来说是只读的 - 使用该服务的任何人都可以完全访问他们这边的字段。
回答by stakx - no longer contributing
There is a way to achieve this. But be warned that it directly violates the following principle cited in this answer:
有一种方法可以实现这一点。但请注意,它直接违反了此答案中引用的以下原则:
"3. Services share schema and contract, not class."
“3. 服务共享模式和契约,而不是类。”
If this violation does not concern you, this is what you do:
如果这种违规行为与您无关,您可以这样做:
Move the service and data contracts into a separate (portable) class library. (Let's call this assembly
SomeService.Contracts.) This is how you'd define an immutable[DataContract]class: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; } }Note that
[DataMember]is applied to the backing field, and notto the corresponding read-only property.Reference the contract assembly from both your service application project (I'll call mine
SomeService.Web) and from your client projects (mine is calledSomeService.Client). This might result in the following project dependencies inside your solution:
Next, when you add the service reference to your client project, make sure to have the option "reuse types" enabled, and ensure that your contract assembly (
SomeService.Contracts) will be included in this:
将服务和数据契约移动到一个单独的(可移植的)类库中。(让我们称之为程序集
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]它应用于支持字段,而不是相应的只读属性。从您的服务应用程序项目(我称为 mine
SomeService.Web)和您的客户端项目(我的称为SomeService.Client)中引用合同程序集。这可能会导致您的解决方案中出现以下项目依赖项:
接下来,当您将服务引用添加到您的客户端项目时,请确保启用“重用类型”选项,并确保您的合同程序集 (
SomeService.Contracts) 将包含在此:
Voilà! Visual Studio, instead of generating a new Footype from the service's WSDL schema, will reuse the immutable Footype from your contract assembly.
瞧!Visual StudioFoo将重用Foo合同程序集中的不可变类型,而不是从服务的 WSDL 架构中生成新类型。
One last warning: You've already strayed from the service principles cited in that other answer. But try not to stray any further. You might be tempted to start adding (business) logic to your data contract classes; don't. They should stay as close to dumb data transfer objects (DTOs) as you can manage.
最后一个警告:您已经偏离了另一个答案中引用的服务原则。但尽量不要再迷路了。您可能想开始向数据契约类添加(业务)逻辑;别。它们应该尽可能地接近愚蠢的数据传输对象 (DTO)。
回答by Simon_Weaver
I had some properties in a class in my service layer I wanted to pass over to Silverlight. I didn't want to create a whole new class.
我的服务层的一个类中有一些属性,我想传递给 Silverlight。我不想创建一个全新的类。
Not really 'recommended', but this seemed the lesser of two evils to pass over the Totalproperty to silverlight (solely for visual databinding).
并不是真正“推荐”,但这似乎是将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");
}
}
}
回答by solairaja
Define the Service contract (Interface) Before implementing the contract using the class.
定义服务契约(Interface) 在使用类实现契约之前。

