none
WCF怎样暴露自己的实体接口? RRS feed

  • 问题

  • 比如说 我有一个实体类 
    public interface IItem
    {
        int  value {get;set;}
    }

    public class Item  :IItem
    {
       IItem.value {get;set;}

    }



    我在WCF的  IService1 中加入

    void Add(IItem itm);


    在客户端只能解析出    "IService1.Add(Object itm);"


    请问应该如何让客户段正确的解析接口?  能做到么?


    答案900, 目标五颗星 Aurvana Air, 音乐真的是随风飘来的 凉宫春日 永无止境的八月 你到底什么时候结束阿。。。。
    2009年8月3日 5:35

答案

  • Hi,
       你的这个情况我没试验过。不过问题应该和序列化有关系。一般情况下用户自己定义的实体类。要想在客户端与服务端共享的话,
    只能是定义为数据契约。这样的话数据在客户端和服务端传递的时候,WCF会调用自己特定的序列化器DataContractSerializer来序列换这个对象。
    你把实体类添加Datacontract属性,如果特定的字段如果想暴露给客户端的话,在加上Datamemeber标记。
    以前英文论坛也有人讨论过这个问题,就是数据契约和实体类的服用问题。为了能使实体类支持数据契约序列化与饭序列化
    可能需要花费一定的时间来标记实体类的数据契约属性。
    另外一种如果客户端也是基于.NET2.0以上 平台的话,也可以使用XML序列化标记,就是在类的生命前,加上Serializable关键字。
      
     
    Frank Xu Lei--谦卑若愚,好学若饥
    专注于.NET平台下分布式应用系统开发和企业应用系统集成
    Focus on Distributed Applications Development and EAI based on .NET
    欢迎访问老徐的中文技术博客:Welcome to My Chinese Technical Blog
    欢迎访问微软WCF中文技术论坛:Welcome to Microsoft Chinese WCF Forum
    欢迎访问微软WCF英文技术论坛:Welcome to Microsoft English WCF Forum
    2009年8月3日 9:02
    版主
  • http://book.51cto.com/art/200908/141215.htm
    5.3.3  基于接口的序列化

    DataContractSerializer的创建必须基于某个确定的类型,这里的类型既可以是接口,也可以是抽象类或具体类。不过基于接口的DataContractSerializer与基于抽象数据契约类型的DataContractSerializer,在进行序列化时表现出来的行为是不相同的。

    在下面的代码中,在调用Serialize<T>的时候,将泛型类型分别设定为接口IOrder和抽象类OrderBase。虽然是对同一个Order对象进行序列化,但是序列化生成的XML却各有不同。文件order.interface.xml的根节点为<z:anyType>,这是因为DataContractAttribute不能应用于接口上面,所以接口不具有数据契约的概念。<z:anyType>表明能够匹配任意类型,相当于类型object。

    1. Order order = new Order()  
    2. {  
    3.     ID = Guid.NewGuid(),  
    4.     Customer = "NCS",  
    5.     Date = DateTime.Today,  
    6.     ShipAddress = "#328, Airport Rd, Industrial
      Park, Suzhou Jiangsu Province"
      ,  
    7.     TotalPrice = 8888.88  
    8. };  
    9.  
    10. Serialize<IOrder>(order, @"E:\order.interface.
      xml", new List
      <Type>{typeof  
    11.   (Order)});  
    12. Serialize<OrderBase>(order, @"E:\order.class.
      xml", new List
      <Type>   
    13.   { typeof(Order) });  
    14. <z:anyType xmlns:i="http://www.w3.org/2001/
      XMLSchema-instance"
         
    15.   xmlns:d1p1="http://schemas.datacontract.org/2004/07/Artech.  
    16.   DataContractSerializerDemos" i:type="d1p1:Order"   
    17.   xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/"> 
    18.     <d1p1:Customer>NCS</d1p1:Customer> 
    19.     <d1p1:Date>2008-12-04T00:00:00+08:00</d1p1:Date> 
    20.     <d1p1:ID>04c07e41-6302-48d1-ac06-87ebbff2b75f</d1p1:ID> 
    21.     <d1p1:ShipAddress>#328, Airport Rd, 
      Industrial Park, Suzhou Jiangsu   
    22.       Province</d1p1:ShipAddress> 
    23.     <d1p1:TotalPrice>8888.88</d1p1:TotalPrice> 
    24. </z:anyType> 
    25. <OrderBase xmlns:i="http://www.w3.org/2001/
      XMLSchema-instance"
       i:type="Order"   
    26.   xmlns="http://schemas.datacontract.org/2004/07/Artech.  
    27.   DataContractSerializerDemos"> 
    28.     <Customer>NCS</Customer> 
    29.     <Date>2008-12-04T00:00:00+08:00</Date> 
    30.     <ID>04c07e41-6302-48d1-ac06-87ebbff2b75f</ID> 
    31.     <ShipAddress>#328, Airport Rd, Industrial Park, Suzhou Jiangsu   
    32.       Province</ShipAddress> 
    33.     <TotalPrice>8888.88</TotalPrice> 
    34. </OrderBase> 

    实际上,在WCF应用中,如果服务契约的操作参数定义为接口,在发布出来的元数据中,接口类型就相当于object,并且当客户端通过添加服务引用生成客户端服务契约的时候,相应的参数类型就是object类型。比如对于下面的服务契约的定义,当客户端导出后将变成后面的样式。

    1. [ServiceContract(Namespace="http://www.artech.com/")]  
    2. public interface IOrderManager  
    3. {  
    4.     [OperationContract]  
    5.     void ProcessOrder(IOrder order);  
    6. }  
    7. [System.CodeDom.Compiler.GeneratedCodeAttribute
      ("System.ServiceModel",   
    8.   "3.0.0.0")]  
    9. [System.ServiceModel.ServiceContract
      Attribute(
      ConfigurationName =   
    10.   "ServiceReferences.IOrderManager")]  
    11. public interface IOrderManager  
    12. {  
    13.  
    14.     [System.ServiceModel.OperationContract
      Attribute(
      Action =   
    15.       "http://www.artech.com/IOrderManager/
      ProcessOrder"
      ReplyAction =   
    16.       "http://www.artech.com/IOrderManager/
      ProcessOrderResponse"
      )]  
    17.     void ProcessOrder(object order);  
    看来只能用Object 了   不过看起来应该没什么问题哦
    答案900, 目标五颗星 Aurvana Air, 音乐真的是随风飘来的 凉宫春日 永无止境的八月 你到底什么时候结束阿。。。。
    2009年8月3日 9:22

全部回复

  • Hi,
       你的这个情况我没试验过。不过问题应该和序列化有关系。一般情况下用户自己定义的实体类。要想在客户端与服务端共享的话,
    只能是定义为数据契约。这样的话数据在客户端和服务端传递的时候,WCF会调用自己特定的序列化器DataContractSerializer来序列换这个对象。
    你把实体类添加Datacontract属性,如果特定的字段如果想暴露给客户端的话,在加上Datamemeber标记。
    以前英文论坛也有人讨论过这个问题,就是数据契约和实体类的服用问题。为了能使实体类支持数据契约序列化与饭序列化
    可能需要花费一定的时间来标记实体类的数据契约属性。
    另外一种如果客户端也是基于.NET2.0以上 平台的话,也可以使用XML序列化标记,就是在类的生命前,加上Serializable关键字。
      
     
    Frank Xu Lei--谦卑若愚,好学若饥
    专注于.NET平台下分布式应用系统开发和企业应用系统集成
    Focus on Distributed Applications Development and EAI based on .NET
    欢迎访问老徐的中文技术博客:Welcome to My Chinese Technical Blog
    欢迎访问微软WCF中文技术论坛:Welcome to Microsoft Chinese WCF Forum
    欢迎访问微软WCF英文技术论坛:Welcome to Microsoft English WCF Forum
    2009年8月3日 9:02
    版主
  • 实体类应该是没问题的  但是[Datamemeber] 是不能加在接口上的 

    public interface IItem
    {
         [.......]
        int  value {get;set;}
    }


    答案900, 目标五颗星 Aurvana Air, 音乐真的是随风飘来的 凉宫春日 永无止境的八月 你到底什么时候结束阿。。。。
    2009年8月3日 9:14
  • http://book.51cto.com/art/200908/141215.htm
    5.3.3  基于接口的序列化

    DataContractSerializer的创建必须基于某个确定的类型,这里的类型既可以是接口,也可以是抽象类或具体类。不过基于接口的DataContractSerializer与基于抽象数据契约类型的DataContractSerializer,在进行序列化时表现出来的行为是不相同的。

    在下面的代码中,在调用Serialize<T>的时候,将泛型类型分别设定为接口IOrder和抽象类OrderBase。虽然是对同一个Order对象进行序列化,但是序列化生成的XML却各有不同。文件order.interface.xml的根节点为<z:anyType>,这是因为DataContractAttribute不能应用于接口上面,所以接口不具有数据契约的概念。<z:anyType>表明能够匹配任意类型,相当于类型object。

    1. Order order = new Order()  
    2. {  
    3.     ID = Guid.NewGuid(),  
    4.     Customer = "NCS",  
    5.     Date = DateTime.Today,  
    6.     ShipAddress = "#328, Airport Rd, Industrial
      Park, Suzhou Jiangsu Province"
      ,  
    7.     TotalPrice = 8888.88  
    8. };  
    9.  
    10. Serialize<IOrder>(order, @"E:\order.interface.
      xml", new List
      <Type>{typeof  
    11.   (Order)});  
    12. Serialize<OrderBase>(order, @"E:\order.class.
      xml", new List
      <Type>   
    13.   { typeof(Order) });  
    14. <z:anyType xmlns:i="http://www.w3.org/2001/
      XMLSchema-instance"
         
    15.   xmlns:d1p1="http://schemas.datacontract.org/2004/07/Artech.  
    16.   DataContractSerializerDemos" i:type="d1p1:Order"   
    17.   xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/"> 
    18.     <d1p1:Customer>NCS</d1p1:Customer> 
    19.     <d1p1:Date>2008-12-04T00:00:00+08:00</d1p1:Date> 
    20.     <d1p1:ID>04c07e41-6302-48d1-ac06-87ebbff2b75f</d1p1:ID> 
    21.     <d1p1:ShipAddress>#328, Airport Rd, 
      Industrial Park, Suzhou Jiangsu   
    22.       Province</d1p1:ShipAddress> 
    23.     <d1p1:TotalPrice>8888.88</d1p1:TotalPrice> 
    24. </z:anyType> 
    25. <OrderBase xmlns:i="http://www.w3.org/2001/
      XMLSchema-instance"
       i:type="Order"   
    26.   xmlns="http://schemas.datacontract.org/2004/07/Artech.  
    27.   DataContractSerializerDemos"> 
    28.     <Customer>NCS</Customer> 
    29.     <Date>2008-12-04T00:00:00+08:00</Date> 
    30.     <ID>04c07e41-6302-48d1-ac06-87ebbff2b75f</ID> 
    31.     <ShipAddress>#328, Airport Rd, Industrial Park, Suzhou Jiangsu   
    32.       Province</ShipAddress> 
    33.     <TotalPrice>8888.88</TotalPrice> 
    34. </OrderBase> 

    实际上,在WCF应用中,如果服务契约的操作参数定义为接口,在发布出来的元数据中,接口类型就相当于object,并且当客户端通过添加服务引用生成客户端服务契约的时候,相应的参数类型就是object类型。比如对于下面的服务契约的定义,当客户端导出后将变成后面的样式。

    1. [ServiceContract(Namespace="http://www.artech.com/")]  
    2. public interface IOrderManager  
    3. {  
    4.     [OperationContract]  
    5.     void ProcessOrder(IOrder order);  
    6. }  
    7. [System.CodeDom.Compiler.GeneratedCodeAttribute
      ("System.ServiceModel",   
    8.   "3.0.0.0")]  
    9. [System.ServiceModel.ServiceContract
      Attribute(
      ConfigurationName =   
    10.   "ServiceReferences.IOrderManager")]  
    11. public interface IOrderManager  
    12. {  
    13.  
    14.     [System.ServiceModel.OperationContract
      Attribute(
      Action =   
    15.       "http://www.artech.com/IOrderManager/
      ProcessOrder"
      ReplyAction =   
    16.       "http://www.artech.com/IOrderManager/
      ProcessOrderResponse"
      )]  
    17.     void ProcessOrder(object order);  
    看来只能用Object 了   不过看起来应该没什么问题哦
    答案900, 目标五颗星 Aurvana Air, 音乐真的是随风飘来的 凉宫春日 永无止境的八月 你到底什么时候结束阿。。。。
    2009年8月3日 9:22
  • 谢谢,我也是学习了新东西~
    Frank Xu Lei--谦卑若愚,好学若饥
    专注于.NET平台下分布式应用系统开发和企业应用系统集成
    Focus on Distributed Applications Development and EAI based on .NET
    欢迎访问老徐的中文技术博客:Welcome to My Chinese Technical Blog
    欢迎访问微软WCF中文技术论坛:Welcome to Microsoft Chinese WCF Forum
    欢迎访问微软WCF英文技术论坛:Welcome to Microsoft English WCF Forum
    2009年8月3日 10:08
    版主
  • 您好,可以考虑用基类来替换接口:

    public abstract class ItemBase  :IItem
    {
        abstract value {get;set;}

    }

    IService1 中加入

    void Add(ItemBase itm);

    虽然也支持多态,但这样会改变该服务契约的语义,传入的参数不再是某个功能集而是一个责任体。这要看具体的需求而定了。
    好处是增强了类型的安全。
    2009年8月3日 14:01
  • 您好,可以考虑用基类来替换接口:

    public abstract class ItemBase  :IItem
    {
        abstract value {get;set;}

    }

    IService1 中加入

    void Add(ItemBase itm);

    虽然也支持多态,但这样会改变该服务契约的语义,传入的参数不再是某个功能集而是一个责任体。这要看具体的需求而定了。
    好处是增强了类型的安全。

    这样是不是还存在客户端无法序列化的问题,估计还是要声明为数据契约
    Frank Xu Lei--谦卑若愚,好学若饥
    专注于.NET平台下分布式应用系统开发和企业应用系统集成
    Focus on Distributed Applications Development and EAI based on .NET
    欢迎访问老徐的中文技术博客:Welcome to My Chinese Technical Blog
    欢迎访问微软WCF中文技术论坛:Welcome to Microsoft Chinese WCF Forum
    欢迎访问微软WCF英文技术论坛:Welcome to Microsoft English WCF Forum
    2009年8月3日 14:18
    版主
  • 是,我忘了给ItemBase加[DataContract]特性了。
    2009年8月3日 14:38
  • 是,我忘了给ItemBase加[DataContract]特性了。


    这样就违背使用接口的最初需求了, 不行啊。

    目前看可能还是要在客户端实现  IRepository<IItem>   数据契约仍然要用实体类 而不是接口。

    如果契约依赖实体类的话   EF/Linq2sql/NH 就要实现三套接口了   不甘心啊。


    答案900, 目标五颗星 Aurvana Air, 音乐真的是随风飘来的 凉宫春日 永无止境的八月 你到底什么时候结束阿。。。。
    2009年8月4日 5:17
  • 是,我忘了给ItemBase加[DataContract]特性了。


    这样就违背使用接口的最初需求了, 不行啊。

    目前看可能还是要在客户端实现  IRepository<IItem>   数据契约仍然要用实体类 而不是接口。

    如果契约依赖实体类的话   EF/Linq2sql/NH 就要实现三套接口了   不甘心啊。


    答案900, 目标五颗星 Aurvana Air, 音乐真的是随风飘来的 凉宫春日 永无止境的八月 你到底什么时候结束阿。。。。

    您好,我之前也遇到这类的问题,因接口的继承跟类和抽象类的继承不同。
    现在对参数和泛型参数都特别小心,在一开始设计时就先确认,这参数是代表接口的功能集,还是代表抽象类的责任体。

    另,从《Programming WCF Services》摘一段跟您发布主题相关的。估计可以做结论了。请参考:

    "You cannot apply the KnownType attribute on the base interface because the interface itself will not be included in the exported metadata. Instead, the exported service contract will be object-based"
    2009年8月4日 6:23