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

本文关键字:数据 服务 WCF | 更新日期: 2023-09-27 17:55:23

我有一个新问题要问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",但我想要一些其他观点。

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

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

您可以为每个服务创建单独的 DTO,但您的案例实际上是装饰器模式的理想选择:

[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 类似的代码,它只公开你关心的东西......

如果它们旨在表示不同类型的用户,则它们应该是不同的类。我同意注释中的phoog,您应该从共享User类派生所需的类型,并将特定的服务属性添加到派生类中。

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

如注释中所建议的,您可以从基本用户派生两个类,然后使用数据协定已知类型,您可以实现所需的目标。有关更多示例,请参阅以下链接。

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

如果您不想使用继承,如下所示:

[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 消息为空时不将该属性发出到 SOAP 消息中,方法是执行以下操作:

    [DataMember(EmitDefaultValue=false)]

然后,当该属性为 null 时,它将不会包含在序列化中。但是,如果客户端是从 WSDL 生成的,则不会产生真正的区别,因为它的用户类型仍然必须包含这两个属性。它只会更改序列化,以便而不是向客户端发送类似的东西:

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

相反,它将发送:

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