WCF:公开未设置的只读 DataMember 属性?

发布于 2024-08-14 12:08:05 字数 796 浏览 10 评论 0原文

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

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.

So - is there a way to have a [DataMember] property without setter?

[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..?

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 */ }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

葬心 2024-08-21 12:08:05

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

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

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

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

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

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

请参阅第 3 点 - 服务共享架构和契约,不是类 - 您只共享数据协定的接口和 XML 架构 - 仅此而已 - 没有 .NET 类。

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 cannot use the server-side class per se!

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.

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!

Check the "Four tenets of SOA" (defined by Don Box of Microsoft):

  1. Boundaries are explicit
  2. Services are autonomous
  3. Services share schema and contract, not class
  4. Compability is based upon policy

See point #3 - services share schema and contract, not class - you only ever share the interface and XML schema for the data contract - that's all - no .NET classes.

此刻的回忆 2024-08-21 12:08:05

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

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

也就是说,请记住,该字段对于使用您的类的人来说是只读的 - 使用该服务的任何人都可以完全访问他们这边的字段。

put DataMember attribute on a field not the property.

Remember thought, that WCF does not know encapsulation. Encapsulation is a OOP term, not a SOA term.

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.

深巷少女 2024-08-21 12:08:05

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

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

如果您不关心此违规行为,则可以执行以下操作:

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

    命名空间 SomeService.Contracts
    {
        [数据合同]
        公共密封类 Foo
        {
            公共 Foo(int x)
            {
                这个.x = x;
            }
    
            公共整数X
            {
                得到
                {
                    返回x;
                }
            }
    
            [DataMember] // 注意:应用于支持字段,而不是属性!
            私有只读 int x;
        }
    }
    

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

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

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

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

    突出显示相关服务引用设置的屏幕截图

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

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

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."

If this violation does not concern you, this is what you do:

  1. 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 not to the corresponding read-only property.

  2. Reference the contract assembly from both your service application project (I'll call mine SomeService.Web) and from your client projects (mine is called SomeService.Client). This might result in the following project dependencies inside your solution:

    screenshot highlighting the project dependencies in Solution Explorer

  3. 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:

    screenshot highlighting the relevant service reference setting

Voilà! Visual Studio, instead of generating a new Foo type from the service's WSDL schema, will reuse the immutable Foo type from your contract assembly.

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.

指尖凝香 2024-08-21 12:08:05

我的服务层中的一个类中有一些属性,我想传递给 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");
        }
    }
}

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.

Not really 'recommended', but this seemed the lesser of two evils to pass over the Total property to silverlight (solely for visual databinding).

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");
        }
    }
}
眼泪都笑了 2024-08-21 12:08:05

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

Define the Service contract (Interface) Before implementing the contract using the class.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文