7

我对 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'原样使用数据库操作,我有什么选择来实现这一点?我真的需要创建不同的数据合约还是有其他更聪明的方法?

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

先感谢您。

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

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

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

4

4 回答 4

4

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

于 2011-05-09T11:08:32.027 回答
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 消息中当它为空时,通过执行:

    [DataMember(EmitDefaultValue=false)]

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

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

它会改为发送:

<User>
  <PropertyVisibleOnlyForService2>something</PropertyVisibleOnlyForService2>
</User>
于 2011-05-06T16:39:22.207 回答
1

正如评论中所建议的,您可以拥有两个派生自基本 User 的类,然后使用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

于 2011-05-06T16:25:19.000 回答
1

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

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

于 2011-05-06T15:59:00.807 回答