非常复杂的问题,涉及当数据不是强类型时,如何通过 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>
原因和其他东西:
首先,我很抱歉这篇文章的长度,但我也想提供可重现的代码。
我想要这种格式,因为我正在使用 PHP 的 Web 服务。 我想轻松去:
这很重要
In PHP => "$Result["StorageObject"]["OtherInfo"]["Hobbies"]".
如果它是其他格式,那么我根本没有办法做到这一点。 此外,在 C# 中,如果我正在使用该服务,我还希望能够执行以下操作:
这很重要
In C# => var m = ServiceResult[0].OtherInfo["Hobbies"];
不幸的是,我不确定如何做到这一点。 我能够通过构建一个实现IXmlSerializer的自定义字典(参见StackOverflow:IXmlSerializer Dictionary(来做到这一点,但是,它使WSDL模式摆脱了困境。 它也太复杂了,在我的WinFormsTester应用程序中产生了可怕的结果!
有什么办法可以做到这一点吗? 我需要创建什么类型的对象? 除了制作强类型集合之外,还有什么方法可以做到这一点吗? 显然,如果我像这样强类型:
public class OtherInfo {
public string Hobbies { get; set; }
public string FavoriteWebsite { get; set; }
}
然后它会完美地工作,我将没有WSDL问题,我将能够轻松地从PHP和C#(.其他信息爱好(。
但是,我将完全失去NVP的重点,因为我必须事先知道列表是什么,并且它是不可更改的......例如,从数据库中。
谢谢大家!! 我希望我们能够为此提出某种解决方案。 以下是要求:
- WSDL 模式不应中断
- 名称值对 (NVP( 应序列化为属性格式
- 应该很容易通过名称访问 PHP 中的 NVP ["爱好"]
- 应该很容易在 C# 中访问(并且与它的代理生成器兼容(
- 易于序列化
- 不需要我强键入数据
现在,我/完全/愿意输入更好/不同的方法来做到这一点。 我正在存储一些相对"静态"的信息(如Name(和一堆数据。 如果有更好的方法,我很想听听。
这类似于对象的动态属性。C#不像javascript那样是一种动态语言,或者PHP可以动态解析对象属性。以下两种方法是我能想到的。第二个可能适合您的要求。
亲吻之道
保持简单愚蠢的方式
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
,另一个方法返回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>
. 然后"爱好"和"网站"将是您的键,值将是爱好或网站的列表。 不过,我不确定它将如何序列化。
您可以将爱好列表引用为:
List<string> hobbies = storageObject.OtherInfo["Hobbies"];
[编辑] 有关通用 XML 可序列化字典,请参阅此处。 此派生类是您需要使用的类,而不是泛型字典。