7

WCFの達人に新しい質問があります。

したがって、Userデータベース操作に使用するDBの「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'。DB操作にはそのまま使用したいのですが'User'、これを実現するための選択肢は何でしょうか。本当に別のデータコントラクトを作成する必要がありますか、それとも別のよりスマートな方法がありますか?

最善の方法は、解決策を提供するだけでなく、いくつかのベストプラクティスと代替案を説明することです。

前もって感謝します。

編集1:概要をわかりやすくするために、ここにダミーのDBLayerクラスを追加しました。この場合、継承が適切でない可能性がある理由を説明します。

解決策は、最後に''から/にマップするデータコントラクトとして別の' UserForService1'と' 'を使用することですが、他の観点が必要でした。UserForService2User

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

さまざまなタイプのユーザーを表すように設計されている場合は、さまざまなクラスにする必要があります。コメントのphoogに同意します。共有ユーザークラスから必要なタイプを派生させ、派生クラスに特定のサービスプロパティを追加する必要があります。

この場合、相続が良いと思いませんか?詳細をお知らせいただければ、実際の問題に合わせて提案を修正することができます。

于 2011-05-06T15:59:00.807 に答える
1

コメントで示唆されているように、ベースユーザーから派生した2つのクラスを作成し、データコントラクトの既知のタイプを使用して、目的の目標を達成できます。その他の例については、次のリンクを参照してください。

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

継承を使用したくない場合は、次のようになります。

[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にパックし、ユーザータイプを定義するのは1回だけなので、そこにあるプロパティを知る必要があります。

ここで、作成される実際のSOAPメッセージだけが気になり、WSDLや、WSDLから生成されたクライアントが何を見るかを気にしない場合、技術的には、そのプロパティをSOAPメッセージに出力しないようにすることができます。 nullの場合、次のようにします。

    [DataMember(EmitDefaultValue=false)]

次に、そのプロパティがnullの場合、シリアル化には含まれません。ただし、クライアントがWSDLから生成された場合、そのユーザータイプには両方のプロパティが含まれている必要があるため、実際の違いはありません。クライアントに次のようなものを送信する代わりに、シリアル化を変更するだけです。

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

代わりに次を送信します:

<User>
  <PropertyVisibleOnlyForService2>something</PropertyVisibleOnlyForService2>
</User>
于 2011-05-06T16:39:22.207 に答える