2009-06-02 2 views
5

WCFでNameValueCollectionをシリアル化しようとしています。あるタイプを別のタイプに追加するように指示する例外が発生し続ける。それらを追加した後、私は最終的にすでにあるNameValueCollectionを使用したWCFシリアル化の問題

タイプ「System.Objectの[]は」同じデータコントラクト名「http://schemas.microsoft.com/2003/10/Serialization/Arrays:ArrayOfanyType」は別のタイプ「System.Collections.ArrayList」は知られているタイプのリストに追加することはできませんを取得しますプレゼント。

契約は次のようになります。

[KnownType(typeof(NameValueCollection))] 
[KnownType(typeof(CaseInsensitiveHashCodeProvider))] 
[KnownType(typeof(CaseInsensitiveComparer))] 
[KnownType(typeof(string[]))] 
[KnownType(typeof(Object[]))] 
[KnownType(typeof(ArrayList))] 
[DataContract] 
public class MyClassDataBase 
{ 
    [DataMember] 
    public NameValueCollection DataCollection = new NameValueCollection(); 
} 

私は本当に私のNameValueColletionをシリアル化できるようにするには何をすべきかを知りません。

もう一つの奇妙なことに、コンパイラーは、CaseInsensitiveHashCodeProviderが廃止予定であることを警告しています。

答えて

9

最高のアイデアはNameValueCollectionArrayListなどの弱いタイプの使用を停止することです。代わりにDictionary<string,string>List<T>を使用してください。

+0

NameValueCollectionは弱く型付けされていますか? – ironsam

+1

私は弱いタイプではなく弱いタイプという言葉を使いました。これにより、ジェネリックの前に導入されたコレクション型のセットに 'N​​ameValueCollection'を含めることを意味します。 –

+0

WCFで辞書を使用すると、デシリアライズがうまくいきません。私はそれを逆直列化するときに何かがオフになっています。 – micahhoover

4

NameValueCollectionは、この使用例ではまったく設計されていないようです。この問題を扱っているthis bloga seriesof blogpostsがあり、a possible solutionを提示しています(はIDictionaryを使用しています)。私はそれをテストしていない。

1

NameValueCollectionはICollectionインターフェイスを直接実装しません。代わりに、NameValueCollectionはNameObjectCollectionBaseを継承します。これはICollectionインターフェイスを実装しており、オーバーロードされたAdd(system.string)メソッドはNameValueCollectionクラスに実装されていません。 XMLSerializerを使用すると、XmlSerializerは汎用のICollectionとしてNameValueCollectionをシリアル化または逆シリアル化しようとします。したがって、既定のAdd(System.String)を検索します。 Add(system.String)メソッドがない場合、例外がスローされます。

XMLシリアル化を使用する代わりに、シリアル化にSoapFormatterクラスを使用します。 SoapFormatterクラスを使用するには、System.Runtime.Serialization.Formatters.Soap.dllへの参照を追加する必要があります。

// Serializing NameValueCollection object by using SoapFormatter 
SoapFormatter sf = new SoapFormatter(); 
Stream strm1 = File.Open(@"C:\datasoap.xml", FileMode.OpenOrCreate,FileAccess.ReadWrite); 
sf.Serialize(strm1,namValColl); 
strm1.Close(); 

// Deserializing the XML file into NameValueCollection object 
// by using SoapFormatter 
SoapFormatter sf1 = new SoapFormatter(); 
Stream strm2 = File.Open(@"C:\datasoap.xml", FileMode.Open,FileAccess.Read); 
NameValueCollection namValColl1 = (NameValueCollection)sf1.Deserialize(strm2); 
strm2.Close(); 
+0

この場合、Dictionary を使用して問題を解決しましたが、これはずっと使いやすくなっています。 – kaze

+0

ew、いいえ、SoapFormatterは使用しないでください。相互運用性が損なわれる。 – Cheeso

+1

@Kaze、あなたが使った解決策は、実際にSaundersが提案したものです。あなたはこの回答を「受け入れた」とマークしましたが、実際には別の回答を使用しました。 – Cheeso

3

別の方法として、ラッパークラスを使用してNameValueCollectionをWCFシリアル化に適合させることができます。次に、各名前と値のペアをコンマ区切りの1つの文字列としてシリアライズする簡単な例を示します。その後、直列化復元時にバックNameValueCollectionにその値を読み取ります

[CollectionDataContract] 
public class NameValueCollectionWrapper : IEnumerable 
{ 
    public NameValueCollectionWrapper() : this(new NameValueCollection()) { } 

    public NameValueCollectionWrapper(NameValueCollection nvc) 
    { 
     InnerCollection = nvc; 
    } 

    public NameValueCollection InnerCollection { get; private set; } 

    public void Add(object value) 
    { 
     var nvString = value as string; 
     if (nvString != null) 
     { 
      var nv = nvString.Split(','); 
      InnerCollection.Add(nv[0], nv[1]); 
     } 
    } 

    public IEnumerator GetEnumerator() 
    { 
     foreach (string key in InnerCollection) 
     { 
      yield return string.Format("{0},{1}", key, InnerCollection[key]); 
     } 
    } 
} 

これは、あなたのDataContractの上の標準[DataMember]プロパティとして型を使用できるようになります。また、標準のWCFシリアル化技術を使用します。

関連する問題