Webサービスを介したカスタムオブジェクトの名前/値ペアのシリアル化
-
05-07-2019 - |
質問
これは、データが厳密に入力されていない場合に、Webサービス呼び出しを介してデータをシリアル化する方法に関する非常に複雑な質問です。できる限りレイアウトしようとします。
サンプルストレージオブジェクト:
[Serializable]
public class StorageObject {
public string Name { get; set; }
public string Birthday { get; set; }
public List<NameValuePairs> OtherInfo { get; set; }
}
[Serializable]
public class NameValuePairs {
public string Name { get; set; }
public string Value { get; set; }
}
使用例:
[WebMethod]
public List<StorageObject> GetStorageObjects() {
List<StorageObject> o = new List<StorageObject>() {
new StorageObject() {
Name = "Matthew",
Birthday = "Jan 1st, 2008",
OtherInfo = new List<NameValuePairs>() {
new NameValuePairs() { Name = "Hobbies", Value = "Programming" },
new NameValuePairs() { Name = "Website", Value = "Stackoverflow.com" }
}
},
new StorageObject() {
Name = "Joe",
Birthday = "Jan 10th, 2008",
OtherInfo = new List<NameValuePairs>() {
new NameValuePairs() { Name = "Hobbies", Value = "Programming" },
new NameValuePairs() { Name = "Website", Value = "Stackoverflow.com" }
}
}
};
return o;
}
Webサービスからの戻り値:
<StorageObject>
<Name>Matthew</Name>
<Birthday>Jan 1st, 2008</Birthday>
<OtherInfo>
<NameValuePairs>
<Name>Hobbies</Name>
<Value>Programming</Value>
</NameValuePairs>
<NameValuePairs>
<Name>Website</Name>
<Value>Stackoverflow.com</Value>
</NameValuePairs>
</OtherInfo>
</StorageObject>
欲しいもの:
<OtherInfo>
<Hobbies>Programming</Hobbies>
<Website>Stackoverflow.com</Website>
</OtherInfo>
理由<!> amp;その他のもの:
まず、投稿の長さについて申し訳ありませんが、再現可能なコードも提供したかったのです。
PHPからWebサービスを使用しているため、この形式で必要です。簡単に行きたい:
//これは重要です
In PHP => "$Result["StorageObject"]["OtherInfo"]["Hobbies"]".
他の形式の場合、それを実現する方法はまったくありません。また、C#でサービスを使用している場合は、次のこともできるようにしたいと考えています。
//これは重要です
In C# => var m = ServiceResult[0].OtherInfo["Hobbies"];
残念ながら、これを達成する方法はわかりません。 IXmlSerializerを実装したカスタムディクショナリを作成することで、この方法で取得できました( StackOverflow:IXmlSerializer辞書)ただし、WSDLスキーマは完全に削除されました。それはあまりにも複雑すぎて、私のWinFormsTesterアプリケーションで恐ろしい結果を生み出しました!
これを達成する方法はありますか?どのタイプのオブジェクトを作成する必要がありますか?強く型付けされたコレクションを作成する以外に、これを行う方法はありますか?明らかに、このように強く型付けすると:
public class OtherInfo {
public string Hobbies { get; set; }
public string FavoriteWebsite { get; set; }
}
それは完全に機能し、WSDLの問題は発生せず、PHPおよびC#(.OtherInfo.Hobbies)から簡単にアクセスできます。
ただし、リストが何であるかを事前に知る必要があるため、NVPのポイントを完全に失い、変更できません。たとえば、データベースから。
みんなありがとう!!これに対する何らかの解決策を考え出すことができれば幸いです。ここに再び要件があります:
- WSDLスキーマが壊れてはいけません
- 名前と値のペア(NVP)は属性形式にシリアル化する必要があります
- [<!> quot; Hobbies <!> quot;]という名前でPHPのNVPに簡単にアクセスできるはずです
- C#で簡単にアクセスできる(プロキシジェネレーターと互換性がある)
- 簡単にシリアル化可能
- データを強く入力する必要はありません
今、私はこれを行うためのより良い/異なる方法で入力を/完全に/開いています。比較的<!> quot; static <!> quot;を保存しています。情報(名前など)、およびデータの束。もっと良い方法があれば、聞いてみたいです。
解決
これは、オブジェクトの動的プロパティのようなものです。 C#はJavaScriptとは異なり、動的な言語ではないか、PHPがその場でオブジェクトプロパティを解析できる可能性があります。次の2つの方法が考えられます。 2つ目は要件に適合する場合があります。
KISS Way
Keep It Simple愚かな方法
public class StorageObject {
public string Name { get; set; }
public string Birthday { get; set; }
public List<string> OtherInfo { get; set; }
}
「|」で区切られた名前と値のペアを持つことができます
OtherInfo = {"Hobbies|Programming", "Website|Stackoverflow.com"}
シリアル化されたフォーム
<StorageObject>
<Name>Matthew</Name>
<Birthday>Jan 1st, 2008</Birthday>
<OtherInfo>
<string>Hobbies|Programming</string>
<string>Website|Stackoverflow.com</string>
</OtherInfo>
</StorageObject>
C#の動的な方法
名前と値のペア部分をXML要素にして、動的に構築できるようにします。
public class StorageObject {
public string Name { get; set; }
public string Birthday { get; set; }
public XElement OtherInfo { get; set; } // XmlElement for dot net 2
}
OtherInfoオブジェクトを要素中心として簡単に構築できます 例えば
XElement OtherInfo = new XElement("OtherInfo");
OtherInfo.Add( ..Hobbies xelement & text value..);
OtherInfo.Add( ..WebSite xelement & text value..);
シリアル化されたフォームは次のようになります
<OtherInfo>
<Hobbies>Programming</Hobbies>
<Website>Stackoverflow.com</Website>
</OtherInfo>
または属性中心として構築
XElement OtherInfo = new XElement("OtherInfo");
OtherInfo.Add( ..nvp xattribute Hobbies & value..);
OtherInfo.Add( ..nvp xattribute WebSite & value..);
<OtherInfo>
<nvp n="Hobbies" v="Programming" />
<nvp n="Website" v="Stackoverflow.com" />
</OtherInfo>
任意の動的言語の場合、プロパティに直接アクセスできます。 残りについては、XMLを読み取ることで値にアクセスできます。 XMLの読み取りは、ほとんどのフレームワークで十分にサポートされています。
他のヒント
これは私が決めたものです。
クラス構造:
public class StorageObject {
public string Name { get; set; }
public string Birthday { get; set; }
[XmlAnyElement("Info")] // this prevents double-nodes in the XML
public XElement OtherInfo { get; set; }
}
使用法:
StorageObject o = new StorageObject();
o.OtherInfo.Add(new XElement("Hobbies","Programming");
o.OtherInfo.Add(new XElement("Website","Stackoverflow.com");
出力:
<Info>
<Hobbies>Programming</Hobbies>
<Website>Stackoverflow.com</Website>
</Info>
皆さんの支援に感謝したいと思います。助けとアイデアに感謝します。
これに対するまったく異なる考え方として、まったく違うやり方で考えてみてはどうでしょうか。シリアル化されたストレージオブジェクトを返すWebサービスメソッドと、OtherInfo
のプロパティ(キー)のリストを返す別のメソッド、および任意のキーの値のリストを返す別のメソッドがあります。確かに、すべてのデータが必要な場合は、Webサービスへのラウンドトリップがより多くかかりますが、ソリューションははるかに単純で柔軟になります。
[Serializable]
public class StorageObject {
public string Name { get; set; }
public string Birthday { get; set; }
[Nonserializable]
public Dictionary<string,List<string>> OtherInfo { get; set; }
}
[WebMethod]
public List<StorageObject> GetStorageObjects() {
// returns list of storage objects from persistent storage or cache
}
[WebMethod]
public List<string> GetStorageObjectAttributes( string name )
{
// find storage object, sObj
return sObj.Keys.ToList();
}
[WebMethod]
public List<string> GetStorageObjectAtributeValues( sting name, string attribute )
{
// find storage object, sObj
return sObj[attribute];
}
System.Xml.Serialization.XmlSerializerAssemblyAttribute属性を確認します。これにより、カスタムクラスレベルのシリアライザーを指定できます。好きなXMLを吐き出すことができます。
これらをすばやく理解するための簡単な方法は、sgen.exeを使用して生成し、Reflectorで覗いてみることです。
-オイシン
これで問題が解決するかどうかはわかりませんが(C#では解決できますが、PHPでは解決できない可能性があります)、Dictionary<string,List<string>> OtherInfo
ではなくList<NameValuePairs>
を使用してみてください。次に、<!> quot;趣味<!> quot;および<!> quot; Websites <!> quot;あなたのキーになり、値は趣味やウェブサイトのリストになります。ただし、どのようにシリアル化されるのかわかりません。
趣味のリストは次のように参照できます。
List<string> hobbies = storageObject.OtherInfo["Hobbies"];
[編集] こちらをご覧ください汎用XMLシリアライズ可能辞書。この派生クラスは、汎用辞書の代わりに使用する必要があるクラスです。