使用Namespace属性来保证数据契约定义的一致性

      为了得到服务所在的数据库中所产生的数据,我在服务中定义了一个自定义的数据契约,用于WCF中的数据交换。不过在客户调用过程中却出现了一个奇怪的问题,明明在服务在得到的数据,可在返回客户的方法中却不能看到数据。通过SvcUtil.exe的生成分析,得到数据契约的的命名空间会带上数据类所在程序集的命名空间,这点与服务契约的方法不一样。如下定义的数据契约:

namespace WCFDataContractTest

{

    [DataContract]

    struct Product

   {

    [DataMember]

    public string Name;

    [DataMember]

    public int Number;

    }

}

    先来看看数据契约类型的定义,这里面定义了两个公共的属性,是为了保证契约的一致性而设的。

[AttributeUsage(AttributeTargets.Enum | AttributeTargets.Struct | AttributeTargets.Class, Inherited=false, AllowMultiple=false)]
public sealed class DataContractAttribute : Attribute
{
    // Fields
    private string name;
    private string ns;

    // Properties
    public string Name{get;set;}
    public string Namespace{get;set;}
     ……
}
   默认情况下WCF会为我们附加默认的命名空间:

http://schemas.datacontract.org/2004/07/WCFDataContractTest

    由此可以看出消息契约命名空间规范:通用命名空间+所在程序集的命名空间

即:”http://schemas.datacontract.org/2004/07”+[namesapce];

    比较一下服务契约的默认名字空间: “http://tempuri.org/”,它的操作契约的名字空间会再加上接口的名字,不会添加所在程序集的命名空间。

    如果要引用服务中定义的数据契约,必须要注意名字空间的使用,否则会造成服务中的数据不能传递到客户端的情况。由此我们可以用以下四种方式来使用服务中所定义的数据契约。

1、 通过在使用VS自带的添加服务引用(SvcUtil.exe)来引用

这种方式在使用IIS托管下是很方便使用的,它可以得到包括数据契约在内的所在服务定义。不过如果是在自托管方式下,就没有那么方便了。这时我们为了得到引用,必须要在服务的绑定中显示设置服务行为的serviceMetadata 节的httpGetEnabled属性,如下所示:

<serviceBehaviors>

   <behavior name="mex">

       <serviceMetadata httpGetEnabled="true" />

   </behavior>

</serviceBehaviors>

现在我们启动自托管,就可以得到数据契约的引用了。

2、 将客户代理定义在服务所在的程序集中

将客户代理定义在服务所在的程序集中,这样代理就会使用服务中所定义的同一个数据契约,就不会存在名字空间不一致的问题。

3、 在客户端中自定义数据契约中显式设置名字空间

如前一个例子所示,我们在客户的契约定义中可以作如下设置,这样就可以顺利地使用所定义的数据契约了(服务端不设置名字空间):

namespace Client

{

        [DataContract(Name = "Product",

            Namespace = "http://schemas.datacontract.org/2004/07/WCFDataContractTest")]

        struct Product

       {

          [DataMember ]

          public string Name{get;set;}

          [DataMember ]

          public int Number{get;set;}

       }

}

4、 在服务和客户的数据契约定义中设置同样的自定义的命名空间

     这样方式不受WCF自定义数据契约的默认的命名空间的限制,这也是最为方便的一种方式。如我们在服务和代理的契约中同时设置数据契约的Namespace属性:

[DataContract(Namespace="http://www.cnblogs.com/suyan010203")]

    总之,在使用数据契约时一定要注意设置名字空间,最好在显示地同时在服务和代理在设置一样的名字空间,这样就可以一致地使用数据契约了,推荐的做法是在WCF中显式地定义自已的名字空间来取代默认的命名空间。(如第4种方式所示)

posted @ 2010-04-28 16:05  suyan010203  Views(2072)  Comments(3Edit  收藏  举报