【问题标题】:serializing generic XML data across WCF web service requests跨 WCF Web 服务请求序列化通用 XML 数据
【发布时间】:2010-10-30 10:08:36
【问题描述】:

我有一个向 WCF 服务发送请求的 Web 应用程序。 WCF 服务获取一个 LINQ 结果集(anon.ilist)并将其作为回复发送回 Web 应用程序。 为了让它快速运行,在 WCF 应用程序中,我使用 copytodatatable 并将其发送到 DataSet 中的我的网络应用程序。

然后,我的 Web 应用程序获取 DataSet 并将其写入 xml,执行一些 xslt 并将结果数据显示在屏幕上。完美的。 ...嗯,不是真的。

我还是(相对)WCF 新手。我知道发送 DataTables/DataSets 有点麻烦。 Web 应用程序需要 xml 格式的数据(用于 xslt 操作),所以我想我会让 WCF Web 服务为我完成 DataTable -> xml 工作,然后简单地用一个漂亮的 XmlDocument 回复客户端 webapp。
但是不能序列化 XmlDocument。

通过 wcf 将 XML 数据发送到客户端的最佳方式是什么?

  • 数据表包含很多列,并且会经常更改,所以我不想创建自己的对象类(具有无数属性)并发送它(因为这是我所做的以前在 wcf 中的大部分时间,它运行良好......但不适合这种情况)。

  • 编辑:将其作为字符串发送也可以....但这肯定不是最佳解决方案吗?

【问题讨论】:

    标签: xml vb.net wcf dataset


    【解决方案1】:

    通过 WCF 发送数据集的唯一问题是它不可互操作 - 即您无法从非 .NET 客户端使用数据集。

    我在几个大型应用程序中工作过,这些应用程序通过 WCF 通过网络发送数据集就很好。只要发送方和接收方都在 .NET 上运行,您应该没问题。

    如果您仍然不想使用数据集,请考虑创建一个 DataContract 类来保存您的数据以通过网络发送。这是跨 WCF 传输数据的经典方式。除非您的 XML 非常复杂(很可能是这样),否则这可能是一个不错的选择。

    如果您还没有,我强烈建议您阅读 Juval Lowy 出色的“Programming WCF Services 2nd Edition”的副本。他有一整章是关于跨 WCF 传输信息的。这是 WCF 圣经。

    【讨论】:

    • 这本书在我面前...
    • :) 这是一本超级密集的书。我建议把第 1 章读几遍,尽管我认为第 3 章是你感兴趣的。不过,不要把我的副本放在我面前。 :)
    【解决方案2】:

    您可以简单地返回一个 XmlElement - 可能是 XmlDocument 实例的 DocumentElement 属性。

    您不必use the XmlSerializer to do this。 DataContractSerializer 是默认值,并且会很好地发回 XmlElement。您不需要实现 IXmlSerializable。

    下面是一些示例代码

    服务接口:

    using System;
    using System.Xml;
    using System.ServiceModel;
    using System.Runtime.Serialization;
    
    namespace Cheeso.Samples.Webservices
    {
        [ServiceContract(Namespace="urn:Cheeso.Samples" )]
        public interface IService
        {
            [OperationContract]
            XmlElement Register(String request);
        }
    } 
    

    请注意,我没有 DataContract(因此也没有 DataMembers),因为我正在发回一个预定义类 (XmlElement) 的实例。

    这是服务实现:

    using System;
    using System.Xml;
    using System.ServiceModel;
    
    namespace Cheeso.Samples.Webservices._2009Jun01
    {
    
        public class Results
        {
            public int Id;
            public Int64 WorkingSet;
            public String Name;
            public String Title;
        }
    
        [ServiceBehavior(Name="WcfXmlElementService",
                         Namespace="urn:Cheeso.Samples",
                         IncludeExceptionDetailInFaults=true)]
    
        public class WcfXmlElementService : IService
        {
            int index = 0;
            public XmlElement Register(string request)
            {
                XmlDocument doc = new XmlDocument();
    
                // can get the doc from anywhere. We use a LINQ-to-Objects result.
    
           // do the LINQ thing
           var processInfo =
           from p in System.Diagnostics.Process.GetProcesses()
           select new Results {
               Id = p.Id,
               WorkingSet = p.WorkingSet64,
               Name = p.ProcessName,
               Title = p.MainWindowTitle
               };
    
           // Note: cannot use an anonymous ilist if we will use XmlSerializer
    
           // serialize that list into the XmlDocument
           using (XmlWriter writer = doc.CreateNavigator().AppendChild())
           {
           var L = processInfo.ToList();
           XmlSerializer s1 = new XmlSerializer(L.GetType());
           s1.Serialize(writer, L);
           }
    
           index++;
    
           // Append some additional elements to the in-memory document.
           XmlElement elem = doc.CreateElement("id");
           elem.InnerText = System.Guid.NewGuid().ToString();
           doc.DocumentElement.AppendChild(elem);
    
           elem = doc.CreateElement("stamp");
           elem.InnerText = DateTime.Now.ToString("G");
           doc.DocumentElement.AppendChild(elem);
    
           elem = doc.CreateElement("in-reply-to");
           elem.InnerText = request;
           doc.DocumentElement.AppendChild(elem);
    
                return doc.DocumentElement;
            }
        }
    }
    

    如果您使用的是 .NET,客户端会获取一个 XmlElement。如果您使用的是其他堆栈,则它将只是该堆栈中的 XmlElement 或 XmlNode。

    回复消息的 XSD 是通用的,如下所示:

    <xs:element name="RegisterResponse">
      <xs:complexType>
        <xs:sequence>
          <xs:element minOccurs="0" name="RegisterResult" nillable="true">
            <xs:complexType>
              <xs:sequence>
                <xs:any minOccurs="0" processContents="lax" /> 
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:sequence>
      </xs:complexType>
    </xs:element>
    

    【讨论】:

      【解决方案3】:

      方法返回的类需要实现IXmlSerializable。

      public XmlContent XmlContent()
      {
          return new XmlContent();
      }
      
      [XmlRoot(ElementName = "div")]
      public class XmlContent : IXmlSerializable
      {
      
          #region IXmlSerializable Members
      
          public System.Xml.Schema.XmlSchema GetSchema()
          {
              return null;
          }
      
          public void ReadXml(XmlReader reader)
          {
              throw new NotImplementedException();
          }
      
          public void WriteXml(XmlWriter writer)
          {
      
          writer.WriteRaw("<p>some text</p>");
      
          }
          #endregion
      }
      

      我还没有找到如何避免序列化根元素(例如,“div”)。

      我也尝试将 XML 作为字符串发送,但它没有按预期输出,即“字符串”是 HTML 编码并包装在标签中。这使得解析非常困难。

      【讨论】:

        【解决方案4】:

        为什么不尝试将 xml 作为字符串发送?

        【讨论】:

        • 发生在我身上,但我只是假设由于数据是 xml,所以 xmldocument 将是最好的数据类型....我已经尝试了几种数据类型工作,我的应用程序确实工作。我只是在寻找最好的、最佳实践的方法。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-09
        相关资源
        最近更新 更多