7

这是一个非常复杂的问题,当数据不是强类型时,如何通过 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 的自定义 Dictionary (请参阅StackOverflow:IXmlSerializer Dictionary),我能够以这种方式获得它,但是,它使 WSDL 模式脱离了水。它也太复杂了,并且在我的 WinFormsTester 应用程序中产生了可怕的结果!

有没有办法做到这一点?我需要创建什么类型的对象?除了制作强类型集合/之外,还有什么方法可以做到这一点/?显然,如果我让它像这样强类型:

public class OtherInfo {
  public string Hobbies { get; set; }
  public string FavoriteWebsite { get; set; }
}

然后它将完美运行,我不会有 WSDL 问题,我将能够轻松地从 PHP 和 C# (.OtherInfo.Hobbies) 访问它。

但是,我将完全失去 NVP 的意义,因为我必须提前知道列表是什么,而且它是不可更改的……比如说,来自数据库。

谢谢大家!!我希望我们能够为此提出某种解决方案。再次提出要求:

  1. WSDL 模式不应中断
  2. 名称值对 (NVP) 应序列化为属性格式
  3. 通过名称 ["Hobbies"] 应该很容易在 PHP 中访问 NVP
  4. 应该很容易在 C# 中访问(并且与它的代理生成器兼容)
  5. 易于序列化
  6. 不需要我强输入数据

现在,我/完全/愿意输入更好/不同的方式来做到这一点。我正在存储一些相对“静态”的信息(如名称)和一堆数据。如果有更好的方法,我很想听听。

4

5 回答 5

5

这就像对象的动态属性。与 javascript 不同,C# 不是一种动态语言,或者 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。

于 2008-11-01T02:17:33.987 回答
4

这就是我所决定的。

班级结构:

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>

我要感谢大家的帮助,我非常感谢他们的帮助和想法。

于 2008-11-01T03:16:47.847 回答
1

作为对此完全不同的看法,为什么不考虑完全不同的做法。有一个 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];
}
于 2008-11-01T03:04:13.800 回答
0

查看 System.Xml.Serialization.XmlSerializerAssemblyAttribute 属性。这使您可以指定自定义类级序列化程序。您将能够吐出您喜欢的任何 XML。

快速了解这些内容的一种快速方法是使用 sgen.exe 生成一个并使用 Reflector 查看它。

-Oisin

于 2008-11-01T02:07:00.657 回答
-1

我不确定这会解决你的问题(它会在 C# 中,但可能不会在 PHP 中),但尝试使用Dictionary<string,List<string>> OtherInfo而不是List<NameValuePairs>. 然后“爱好”和“网站”将是您的键,值将是爱好或网站的列表。不过,我不确定它会如何序列化。

您可以将爱好列表引用为:

List<string> hobbies = storageObject.OtherInfo["Hobbies"];

[编辑] 请参阅此处以获取通用 XML 可序列化字典。这个派生类是您需要使用的,而不是通用字典。

于 2008-11-01T02:03:55.637 回答