C# 通过 Web 服务序列化自定义对象中的名称/值对
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/255400/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Serializing Name/Value Pairs in a Custom Object via Web Service
提问by Matthew M.
This is a very complicated question concerning how to serialize data via a web service call, when the data is not-strongly typed. I'll try to lay it out as best possible.
这是一个非常复杂的问题,当数据不是强类型时,如何通过 Web 服务调用序列化数据。我会尽量把它摆好。
Sample Storage Object:
样本存储对象:
[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; }
}
Sample Use:
样品用途:
[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;
}
Return Value from Web Service:
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>
What I want:
我想要的是:
<OtherInfo>
<Hobbies>Programming</Hobbies>
<Website>Stackoverflow.com</Website>
</OtherInfo>
The Reason & Other Stuff:
原因和其他东西:
First, I'm sorry for the length of the post, but I wanted to give reproducible code as well.
首先,我很抱歉这篇文章的长度,但我也想提供可重现的代码。
I want it in this format, because I'm consuming the web services from PHP. I want to easily go:
我想要这种格式,因为我正在使用 PHP 中的 Web 服务。我想轻松去:
// THIS IS IMPORANT
// 这很重要
In PHP => "$Result["StorageObject"]["OtherInfo"]["Hobbies"]".
If it's in the other format, then there would be no way for me to accomplish that, at all. Additionally, in C# if I am consuming the service, I would also like to be able to do the following:
如果它是另一种格式,那么我根本无法做到这一点。此外,在 C# 中,如果我正在使用该服务,我还希望能够执行以下操作:
// THIS IS IMPORANT
// 这很重要
In C# => var m = ServiceResult[0].OtherInfo["Hobbies"];
Unfortunately, I'm not sure how to accomplish this. I was able to get it this way, by building a custom Dictionary that implemented IXmlSerializer (see StackOverflow: IXmlSerializer Dictionary), however, it blew the WSDL schema out of the water. It's also much too complicated, and produced horrible results in my WinFormsTester application!
不幸的是,我不确定如何实现这一点。通过构建一个实现 IXmlSerializer 的自定义字典(请参阅StackOverflow: IXmlSerializer Dictionary),我能够通过这种方式获得它,但是,它使 WSDL 模式脱离了水。它也太复杂了,并且在我的 WinFormsTester 应用程序中产生了可怕的结果!
Is there any way to accomplish this ? What type of objects do I need to create ? Is there any way to do this /other than by making a strongly typed collection/ ? Obviously, if I make it strongly typed like this:
有什么办法可以做到这一点吗?我需要创建什么类型的对象?除了制作强类型集合/之外,还有什么方法可以做到这一点吗?显然,如果我像这样强输入:
public class OtherInfo {
public string Hobbies { get; set; }
public string FavoriteWebsite { get; set; }
}
Then it would work perfectly, I would have no WSDL issues, I would be able to easily access it from PHP, and C# (.OtherInfo.Hobbies).
然后它会完美运行,我不会有 WSDL 问题,我将能够轻松地从 PHP 和 C# (.OtherInfo.Hobbies) 访问它。
However, I would completely lose the point of NVP's, in that I would have to know in advance what the list is, and it would be unchangeable.. say, from a Database.
但是,我会完全失去 NVP 的意义,因为我必须事先知道列表是什么,而且它是不可更改的……比如说,从数据库中。
Thanks everyone!! I hope we're able to come up with some sort of solution to this. Here's are the requirements again:
谢谢大家!!我希望我们能够想出某种解决方案。这里又是要求:
- WSDL schema should not break
- Name value pairs (NVP's) should be serialized into attribute format
- Should be easy to access NVP's in PHP by name ["Hobbies"]
- Should be easy to access in C# (and be compatible with it's Proxy generator)
- Be easily serializable
- Not require me to strongly type the data
- WSDL 模式不应中断
- 名称值对 (NVP) 应序列化为属性格式
- 应该很容易通过名称在 PHP 中访问 NVP [“爱好”]
- 应该很容易在 C# 中访问(并与它的代理生成器兼容)
- 易于序列化
- 不需要我强输入数据
Now, I am /completely/ open to input on a better/different way to do this. I'm storing some relatively "static" information (like Name), and a bunch of pieces of data. If there's a better way, I'd love to hear it.
现在,我/完全/愿意以更好/不同的方式来输入。我正在存储一些相对“静态”的信息(如名称)和一堆数据。如果有更好的方法,我很想听听。
采纳答案by Ray Lu
This is like dynamic properties for a object. C# is not quite a dynamic language unlike javascript or maybe PHP can parse the object properties on the fly. The following two methods are what I can think of. The second one might fit into your requirements.
这就像对象的动态属性。与 javascript 不同,C# 并不是一种动态语言,或者 PHP 可以动态解析对象属性。以下两种方法是我能想到的。第二个可能符合您的要求。
The KISS Way
亲吻方式
The Keep It Simple Stupid way
保持简单愚蠢的方式
public class StorageObject {
public string Name { get; set; }
public string Birthday { get; set; }
public List<string> OtherInfo { get; set; }
}
You can have name value pairs which is separated by '|'
您可以拥有以“|”分隔的名称值对
OtherInfo = {"Hobbies|Programming", "Website|Stackoverflow.com"}
Serialized forms
序列化表格
<StorageObject>
<Name>Matthew</Name>
<Birthday>Jan 1st, 2008</Birthday>
<OtherInfo>
<string>Hobbies|Programming</string>
<string>Website|Stackoverflow.com</string>
</OtherInfo>
</StorageObject>
The Dynamic Way in C#
C#中的动态方式
Make the name value pair part become an XML element so that you can build it dynamically.
使名称值对部分成为一个 XML 元素,以便您可以动态构建它。
public class StorageObject {
public string Name { get; set; }
public string Birthday { get; set; }
public XElement OtherInfo { get; set; } // XmlElement for dot net 2
}
You can easily build up OtherInfo object as element centric e.g.
您可以轻松地将 OtherInfo 对象构建为以元素为中心的,例如
XElement OtherInfo = new XElement("OtherInfo");
OtherInfo.Add( ..Hobbies xelement & text value..);
OtherInfo.Add( ..WebSite xelement & text value..);
The serialized form will be
序列化的形式将是
<OtherInfo>
<Hobbies>Programming</Hobbies>
<Website>Stackoverflow.com</Website>
</OtherInfo>
or build it as attribute centric
或将其构建为以属性为中心
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>
For any dynamic language, it can access to the properties directly. For the rest, they can access the value by read the XML. Reading XML is well supported by most of framework.
对于任何动态语言,它都可以直接访问属性。对于其余的,他们可以通过读取 XML 来访问该值。大多数框架都很好地支持读取 XML。
回答by tvanfosson
I'm not sure this would solve your problem (it would in C#, but maybe not in PHP), but try using Dictionary<string,List<string>> OtherInfo
instead of List<NameValuePairs>
. Then "Hobbies" and "Websites" would be your keys and the values would be the list of hobbies or web sites. I'm not sure how it would serialize, though.
我不知道这会解决您的问题(它会在C#中,但在PHP也许不是),而是尝试使用Dictionary<string,List<string>> OtherInfo
替代List<NameValuePairs>
。然后“爱好”和“网站”将是您的键,而值将是爱好或网站的列表。不过,我不确定它会如何序列化。
You would be able to reference the lists of hobbies as:
您可以将爱好列表引用为:
List<string> hobbies = storageObject.OtherInfo["Hobbies"];
[EDIT] See herefor a generic XML serializable dictionary. This derived class is the one you would need to use instead of generic Dictionary.
[编辑] 有关通用 XML 可序列化字典,请参见此处。这个派生类是您需要使用的类,而不是通用 Dictionary。
回答by x0n
Have a look into the System.Xml.Serialization.XmlSerializerAssemblyAttribute attribute. This lets you specify a custom class-level serializer. You'll be able to spit out whatever XML you like.
查看 System.Xml.Serialization.XmlSerializerAssemblyAttribute 属性。这使您可以指定自定义类级序列化程序。您将能够吐出您喜欢的任何 XML。
A quick way to get up to speed on these is to use sgen.exe to generate one and have a peek at it with Reflector.
快速了解这些的一种快速方法是使用 sgen.exe 生成一个并使用 Reflector 查看它。
-Oisin
-Oisin
回答by tvanfosson
As a completely different take on this, why not think about doing it completely differently. Have one web service method to return the serialized storage object, minus the OtherInfo
and another method to return the list of properties (keys) for OtherInfo
, and a third to return the list of values for any key. Granted, it will take more round trips to the web service if you want all of the data, but the solution will be much simpler and more flexible.
作为对此完全不同的看法,为什么不考虑完全不同的做法。有一个 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];
}
回答by Matthew M.
This is what I've settled on.
这就是我所定下的。
Class Structure:
班级结构:
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; }
}
Usage:
用法:
StorageObject o = new StorageObject();
o.OtherInfo.Add(new XElement("Hobbies","Programming");
o.OtherInfo.Add(new XElement("Website","Stackoverflow.com");
Output:
输出:
<Info>
<Hobbies>Programming</Hobbies>
<Website>Stackoverflow.com</Website>
</Info>
I would like to thank everyone for their assistance, I really appreciate the help and ideas.
我要感谢大家的帮助,我非常感谢他们的帮助和想法。