【问题标题】:Constructor in WCF DataContract not reflected on ClientWCF DataContract 中的构造函数未反映在客户端上
【发布时间】:2011-09-13 01:16:50
【问题描述】:

当我在客户端上创建 DataContract 的实例时,我需要让一些数据成员获取一些值。使用构造函数不会发生这种情况。我搜索了不同的论坛,发现我们必须使用 [OnDeserializing] 和 [OnDeserialized] 属性。这也行不通。有人可以在这里提出一些建议。另一种选择是在客户端的部分类中创建构造函数。我想避免这种情况。

请在下面找到代码:

服务器端:数据合约

[DataContract]
public class Account
{

    private int mAccountId;
    private string mAccountName;

    public Account()
    {
        mAccountId = 5;
        mAccountName = "ABC";
    }

    [OnDeserializing]
    public void OnDeserializing(StreamingContext context)
    {
        mAccountId = 5;
        mAccountName = "ABC"; 
    }

    [OnDeserialized]
    public void OnDeserialized(StreamingContext context) 
    {

    } 

    [DataMember]
    public int AccountId
    {
        get
        {
            return mAccountId;
        }
        set
        {
            mAccountId = value;
        }
    }

    [DataMember]
    public string AccountName
    {
        get
        {
            return mAccountName;
        }
        set
        {
            mAccountName = value;
        }
    }


}

客户端 - 初始化

namespace TestClient
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Account acc = new Account();

        }
    }
}

【问题讨论】:

  • WCF 客户端-服务器连接将反映您的数据合同的数据方面 - 您可能在数据类中拥有的任何代码。毕竟:只有数据可以序列化为由 XSD(XML 模式)表示的格式并通过网络发送 - 没有代码。

标签: wcf datacontract


【解决方案1】:

具有DataMember 属性的属性仅定义将包含在生成的 WSDL/XSD 中的内容。客户端将基于 wsdl/xsd 生成自己的 类,用于与服务通信。它不使用服务器上使用的 same 类。

这就是为什么你不会得到:

  • DataContract 类中定义的任何构造函数
  • 任何私有 [DataMember] 属性/字段(客户端将始终生成公共属性/字段)
  • DataContract 类中定义的任何行为

想象一下 Java 客户端想要连接到您的服务的场景。您是否希望使用相同的构造函数生成 java 类? [OnDeserialized] 属性呢? java脚本客户端,python客户端呢?

当你开始以这种方式思考它时,你就会开始明白为什么你不能拥有你想要的东西(至少在客户端和服务器之间不共享库的情况下是这样)。

现实情况是,您不能强制客户端具有始终具有默认值的类,并且您不能让客户端始终发送回有效数据,客户端始终可以发送包含垃圾的消息(如果需要)。您可以使用IsRequired 和“EmitDefaultValue”对消息的某些方面进行一些控制,这将在 xsd 中添加检查以确保消息中存在某些内容,但是您必须在服务器上进行验证,您可以不要假设您返回的对象将被验证。

我的建议是从您的域对象创建 DTO 以通过网络发送,其中不包含任何类型的检查,它们只是用于保存数据的简单袋子。然后创建工厂将您的域对象转换为 DTO 并将 DTO 转换为客户端对象。工厂只是获取 DTO 并将成员传递给域对象的构造函数。然后您的验证逻辑可以存在于它所属的域对象的构造函数中。使用您目前拥有的方法,您最终可能会稍微扭曲验证,以便可以从构造函数和 [OnDeserialized] 方法中完成。

【讨论】:

    【解决方案2】:

    用于创建 WCF 代理类的代码生成器创建兼容的协定类型,并且不使用与 WCF 服务使用的完全相同的类型。实现您想要的最简单的方法是在您的客户端上自己创建构造函数,因为生成的代码是partial

    partial class Account
    {
        public Account()
        {
            AcountId = 5;
            AccountName = "ABC";
        }
    }
    

    如果您不想这样做,您可以让 WCF 重用您的客户端项目已经引用的类型。因此,如果您的数据协定类位于单独的库中(如推荐的那样),您可以引用该库,然后重新配置您的 WCF 客户端项目以重用引用程序集中的共享类型。

    【讨论】:

    • 还有其他解决方法吗?为什么 [OnDeserializing]/[OnDeserialized] 属性不起作用.....谢谢...
    • 因为这些属性用于反序列化 = 当您从服务获取 Account 时而不是在您调用构造函数时!
    • +1 用于将数据合同类放在另一个库中。我们已将它们与服务接口定义一起放入库中,实际上通信契约是服务关注点,而不是域模型关注点。
    【解决方案3】:

    在您的客户端制作代理类:

    public class AccountProxy: Account
    {
       public AccountProxy()
       {
             mAccountId = 5;
             mAccountName = "ABC";
       }
    }
    

    并使用您的代理类,而不是生成的客户端类:

    namespace TestClient
    {
        public partial class _Default : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                AccountProxy acc = new AccountProxy();
    
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-06
      • 2015-03-11
      • 1970-01-01
      • 2011-04-30
      • 1970-01-01
      相关资源
      最近更新 更多