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

时间:2011-05-06 14:55:24

标签: c# wcf service contracts

我有一个关于WCF大师的新问题。

所以,我有一个类User,它接近我用于数据库操作的DB的'User'表示。现在,我希望有两个不同的服务合同,使用这个类作为数据合同,但每个都以他们自己的方式......我的意思是,

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'作为数据库操作,我可以选择实现这一目标吗?我真的需要创建不同的数据合同还是有另一种更聪明的方式?

最好不仅要给我解决方案,还要向我解释一些最佳实践和替代方案。

提前谢谢。

EDIT1: 我在这里添加了一个虚拟DBLayer类,以便更好地概述,以及为什么我认为在这种情况下继承可能不太好。

解决方案是将另一个“UserForService1”和“UserForService2”作为数据合同,这些合同最终会从/ {User'映射,但我想要其他一些观点。

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

4 个答案:

答案 0 :(得分:4)

您可以为每项服务创建单独的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类似的代码,只公开你关心的内容......

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

根据评论中的建议,您可以使用基本用户派生两个类,然后使用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

答案 3 :(得分:1)

如果您不想使用继承,请执行以下操作:

[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消息为null时,执行:

    [DataMember(EmitDefaultValue=false)]

然后当该属性为null时,它不会包含在序列化中。如果客户端是从WSDL生成的,那将没有什么区别,因为它的User类型仍然必须包含这两个属性。它只会改变序列化,而不是像客户端那样发送客户端:

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

它会发送:

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