7

次の ServiceContract および DataContract クラスがあります。

[ServiceContract] 
public interface IWcfService 
{ 
    [OperationContract] 
    Response GetData(); 
} 

[DataContract]
public class Response 
{ 
    [DataMember] 
    public Dictionary<string, object> Data { get; set; } 
} 

Response.Data ディクショナリの値が int、string、double、またはその他の単純なプリミティブ型の場合、WCF はオブジェクトを正常にシリアル化できます。しかし、Response.Data ディクショナリの値が List< string> 型の場合、データを受信して​​逆シリアル化しようとすると、クライアントは次の例外をスローしました。

Message=The formatter threw an exception while trying to deserialize the message: 
There was an error while trying to deserialize parameter http://tempuri.org/:GetDataResult. 
The InnerException message was 'Error in line 1 position 990. 
    Element 'http://schemas.microsoft.com/2003/10/Serialization/Arrays:Value' contains data from a type 
    that maps to the name 'http://schemas.microsoft.com/2003/10/Serialization/Arrays:ArrayOfstring'. 
    The deserializer has no knowledge of any type that maps to this name. 
    Consider using a DataContractResolver or add the type corresponding to 'ArrayOfstring' 
    to the list of known types - for example, by using the KnownTypeAttribute attribute or 
    by adding it to the list of known types passed to DataContractSerializer.'.

また、次のように、KnownType 属性を ServiceContract および DataContract に追加しようとしました。

[ServiceContract] 
[ServiceKnownType(typeof(List<string>))] 
[ServiceKnownType(typeof(Dictionary<string, string>))] 
[ServiceKnownType(typeof(Dictionary<string, List<string>>))] 
public interface IWcfService 
{ 
    [OperationContract] 
    [ServiceKnownType(typeof(List<string>))] 
    [ServiceKnownType(typeof(Dictionary<string, string>))] 
    [ServiceKnownType(typeof(Dictionary<string, List<string>>))] 
    Response GetData(); 
} 

[DataContract] 
[ServiceKnownType(typeof(List<string>))] 
[ServiceKnownType(typeof(Dictionary<string, string>))] 
[ServiceKnownType(typeof(Dictionary<string, List<string>>))] 
[KnownType(typeof(List<string>))] 
[KnownType(typeof(Dictionary<string, string>))] 
[KnownType(typeof(Dictionary<string, List<string>>))] 
public class Response 
{ 
    [DataMember] 
    public Dictionary<string, object> Data { get; set; } 
} 

しかし、これはどれも役に立ちませんでした。誰でもこれについて何か考えがありますか?

更新しました

データは次のようになります。

Data = new new DIctionary<string, object> 
       { 
           {"_id", 12344}, 
           {"names", new List<string>{ "John", "Peter", "Jack"}}, 
           {"time", DateTime.Now} 
       }

Dictionary< string, object> を使用した理由: サーバーは、int、List、DataTime などの「動的」データの辞書をクライアントに送信する必要があります。Dictionary を使用してこの問題を解決するのに役立ちますが、元の型情報も失われます。たとえば、クライアントは List を必要とし、コレクションを表示するために何らかのデータ バインディングを行うため、この場合 List.ToString() は役に立ちません。

4

3 に答える 3

1

System.Objectデフォルトではそうではないと思いますSerializable。Extra 情報を送信する必要がありますが、それでもベスト プラクティスではありません。辞書を使用する前に別の型を定義することをお勧めします。

以下を参照してください。

辞書の配列を返す WCF サービス

WCF System.Object のシリアル化

WCF での IDictionary のシリアル化

于 2013-10-21T10:24:18.310 に答える
1

データ コントラクトはネットワーク経由で文字列にシリアル化されるため、渡すオブジェクトはシリアル化可能でなければならないことに注意してください (そうでobjectはありません)。

問題は、サービス指向のコンテキストでオブジェクト指向のパターンを使用していることです。辞書の値に渡すすべてのものがポリモーフィックであると期待していますobject。ここで同様の「におい」があった質問に答えました: https://stackoverflow.com/a/19445875/2382536

この問題は、WCF がサービスの基盤となるチャネルを抽象化するのに非常に優れているため、「サービス指向」のコンテキストで作業していることを忘れたくなる (KnownTypesはハックであり、OO の錯覚を与える)という事実に起因します。ワイヤー)。データ コントラクトは、サービスに対する "パブリック" API の一部を形成するため、サービスが公開するデータを明確に明示的に表現する必要があります。「動的」データを返すデータ構造を持つことは、この重要な規則に違反します。

クライアントは、返されるデータを知る必要があるため、「動的な」応答を実装する場合は、応答のバリエーションに対してさまざまなメソッド/エンドポイント/サービスを (たとえば) 実装する必要があります。サービス内では、ポリモーフィズムを使用してコードを単純化できない理由はありませんが、これがパブリック サービス/データ コントラクトに漏れてはなりません。

于 2013-10-21T11:52:39.217 に答える
1

皆様のご意見をお寄せいただきありがとうございます。シリアライザーとして NetDataContractSerializer を使用するように WCF を構成することで、問題を解決できました (デフォルトは DataContractSerializer です)。NetDataContractSerializer は、シリアル化を実行するときに、より多くの CLR 型情報を含めますが、パフォーマンスは低下します (シリアル化時間は約 2 倍になります)。

于 2013-11-25T12:17:02.650 に答える