WCF - 使用完全相同的数据合同的多个服务合同

Posted

技术标签:

【中文标题】WCF - 使用完全相同的数据合同的多个服务合同【英文标题】:WCF - multiple service contracts using pretty same data contracts 【发布时间】:2011-08-20 06:26:51 【问题描述】:

我有一个新问题要问 WCF 专家。

所以,我有一个类User,它与我用于数据库操作的数据库中的“用户”表示很接近。现在,我想要 2 个不同的服务合同,将此类用作数据合同,但每个服务合同都有自己的方式......我的意思是,

public class DBLayer

    void InsertUsers(List<User> userList)
    
        // both 'PropertyVisibleForService1' and 'PropertyVisibleForService2'
        // are used HERE to be inserted into their columns 
    


[DataContract]
public class User

  [DataMember] public string PropertyVisibleOnlyForService1...
  [DataMember] public string PropertyVisibleOnlyForService2...


[ServiceContract]
public interface IService1  
   
   List<User> GetUsers();  // user with 'PropertyVisibleOnlyForService1' inside


[ServiceContract]
public interface IService2  
   
    List<User> GetUsers(); // user with 'PropertyVisibleOnlyForService2' inside 

因此,这个想法是每个服务将获得不同类型的用户,'User' 的子集。请记住,我想将'User' 原样用于数据库操作,我有什么选择来实现这一目标?我真的需要创建不同的数据合约还是有其他更智能的方法?

最好的办法是不仅给我解决方案,还给我解释一些最佳实践和替代方案。

提前谢谢你。

编辑1: 我在这里添加了一个虚拟 DBLayer 类以获得更好的概述,以及为什么我认为在这种情况下继承可能不好。

解决方案是使用另一个“UserForService1”和“UserForService2”作为数据合约,它们最终会从/映射到“User”,但我想要一些其他的观点。

EDIT2:非常好的文章在这种情况下对我有帮助:http://bloggingabout.net/blogs/vagif/archive/2009/03/29/iextensibledataobject-is-not-only-for-backward-compatibility.aspx

【问题讨论】:

我不是 WCF 专家,所以通过评论建议:听起来你应该有两个派生自 User 的类;一个具有 PropertyVisibleOblyForService1 属性,另一个具有另一个属性。 感谢您的回复...所以,您建议将这些属性取出并放入新的派生类中。问题是我希望“用户”类保持不变。 是的,我想你理解我的建议。但由于我不是 WCF 专家,而且我不知道您的项目、要求等,我不知道是否可以做您想做的事情,让 User 类保持不变。如果您发布更多详细信息,我可能会有所帮助,或者有更多 WCF 经验的人会参与进来。无论哪种方式都祝您好运! 感谢您的参与,欢迎任何 cmets。我知道一种解决方案是创建 2 个不同的数据合同,然后将“用户”映射到适当的数据合同,但对于这种情况来说,这可能是另一种更好的做法。我真的不认为在我的情况下继承会很好。谢谢。 好的,所以每个人都提出了同样的建议。也许我对我的要求不够清楚。我不想从“用户”中取出属性并放入其他派生类中,因为这个“用户”(及其属性按原样用于数据库操作)。因此,“PropertyVisibleOnlyForService1”和“PropertyVisibleOnlyForService2”都是用户表中的列。 【参考方案1】:

您可以为每个服务创建单独的 DTO,但您的情况实际上是 Decorator pattern 的理想选择:

[DataContract]
public class UserForService1 : User

     private User mUser;
     public UserForService1(User u)
     
         mUser = u;
     

     //expose only properties you'd like the user of this data contract to see
     [DataMember]
     public string SomeProperty
     
         get
         
            //always call into the 'wrapped' object
            return mUser.SomeProperty;
         
         set
         
            mUser.SomeProperty = value;
         
     
     // etc...

对于 Service2 类似的代码,它只公开你关心的内容......

【讨论】:

这是我一直在寻找的答案。非常好的一个!干杯!【参考方案2】:

如果它们旨在代表不同类型的用户,它们应该是不同的类。我同意 cmets 中的 phoog,您应该从共享的 User 类中派生出您想要的类型,并将特定的服务属性添加到派生类中。

您为什么不认为在这种情况下继承会很好?如果您提供更多详细信息,我们可以尝试修改建议以适合您的实际问题。

【讨论】:

【参考方案3】:

正如评论中所建议的,您可以从基本用户派生两个类,然后使用Data Contract Known Types,您可以实现您想要的目标。有关更多示例,请参见以下链接。

http://www.freddes.se/2010/05/19/wcf-knowntype-attribute-example/

http://footheory.com/blogs/bennie/archive/2007/07/28/handling-data-contract-object-hierarchies-in-wcf.aspx

【讨论】:

鉴于 'User' 将 'PropertyVisibleOnlyForService1' 和 'PropertyVisibleOnlyForService2' 用于 db 操作,因为它们是 db 表中的列......这意味着我无法从 'User 中取出这些属性' 将它们放入派生类,除非我以某种方式隐藏它们?也许我应该试一试。【参考方案4】:

如果您不想使用继承,例如:

[DataContract]
public class User



[DataContract]
public class Service1User : User

  [DataMember] public string PropertyVisibleOnlyForService1...


[DataContract]
public class Service2User : User

  [DataMember] public string PropertyVisibleOnlyForService2...


[ServiceContract]
public interface IService1  
   
   List<Service1User> GetUsers();  // user with 'PropertyVisibleOnlyForService1' inside


[ServiceContract]
public interface IService2  
   
    List<Service2User> GetUsers(); // user with 'PropertyVisibleOnlyForService2' inside 

那我不知道你会怎么做。你在那一点上打破了类型声明的原则。以正常的 .NET 方式考虑它;如果您在应用程序中定义“用户”,那么它在任何地方都是相同的类型。某些属性不能对某些其他类或方法隐藏。

WCF 也会把这个类型信息打包到生成的 WSDL 中,而且它只会定义一次 User 类型,所以它需要知道有哪些属性。

现在,如果您只关心构建的实际 SOAP 消息,而不关心 WSDL 或任何从 WSDL 生成的客户端会看到什么,那么从技术上讲,您可以让它不将该属性发送到当 SOAP 消息为空时,执行以下操作:

    [DataMember(EmitDefaultValue=false)]

那么当该属性为空时,它不会被包含在序列化中。但是,如果客户端是从 WSDL 生成的,那将没有真正的区别,因为它的 User 类型仍然必须包含这两个属性。它只会改变序列化,而不是向客户端发送类似的东西:

<User>
  <PropertyVisibleOnlyForService1 nil="true" />
  <PropertyVisibleOnlyForService2>something</PropertyVisibleOnlyForService2>
</User>

它会改为发送:

<User>
  <PropertyVisibleOnlyForService2>something</PropertyVisibleOnlyForService2>
</User>

【讨论】:

感谢您的观点以及如何使用“Emit”的东西。我认为有它的想法很好,也许我将来可以使用它。

以上是关于WCF - 使用完全相同的数据合同的多个服务合同的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在 WCF 的数据合同中使用 DataMember 装饰多个属性?

WCF IIS 托管服务由单个服务实现的多个服务合同 - 如何通过配置在端点之间共享 uri

wcf 决策:一项服务多项合同或多项服务

具有多个合同的 Mono WCF 休息服务“配置文件中未定义端点”

引用相同数据协定的多个 WCF 服务

WCF 数据合同