【问题标题】:Using CDATA with WCF REST starter kits将 CDATA 与 WCF REST 入门工具包一起使用
【发布时间】:2009-09-03 15:17:20
【问题描述】:

我有一个使用 WCF REST 入门工具包的 Preview 2 构建的服务,但在调用中传递 XML 样式的数据时遇到了问题。这是我的请求对象:

[DataContract(Namespace = "")]
public class ServiceRequest
{
    [DataMember]
    public string ContentText { get; set; }
    [DataMember]
    public string ApiKey { get; set; }

}

在你把 '' 扔进去之前,一切都很好。是否可以将 ContentText 属性封装在 CDATA 或类似的东西中?

【问题讨论】:

    标签: c# wcf rest


    【解决方案1】:

    Marc Gravell 有一个解决方案 here 用于序列化 CDATA 部分。

    我在这里复制了代码以供后代使用。

    更新:前面的示例没有生成有效的架构,XmlSchemaProviderAttribute 和伴随的方法将生成“xs:string”,它可以工作[more...]

    using System;
    using System.IO;
    using System.Runtime.Serialization;
    using System.Xml;
    using System.Xml.Serialization;
    using System.ComponentModel;
    
    [XmlSchemaProvider("GenerateSchema")]
    public sealed class CDataWrapper : IXmlSerializable
    {
      // implicit to/from string
      public static implicit operator string(CDataWrapper value)
      {
        return value == null ? null : value.Value;
      }
    
      public static implicit operator CDataWrapper(string value)
      {
        return value == null ? null : new CDataWrapper { Value = value };
      }
    
      public System.Xml.Schema.XmlSchema GetSchema()
      {
        return null;
      }
    
      // return "xs:string" as the type in scheme generation
      public static XmlQualifiedName GenerateSchema(XmlSchemaSet xs)
      {
          return XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.String).QualifiedName;
      }
    
      // "" => <Node/>
      // "Foo" => <Node><![CDATA[Foo]]></Node>
      public void WriteXml(XmlWriter writer)
      {
        if (!string.IsNullOrEmpty(Value))
        {
          writer.WriteCData(Value);
        }
      }
    
      // <Node/> => ""
      // <Node></Node> => ""
      // <Node>Foo</Node> => "Foo"
      // <Node><![CDATA[Foo]]></Node> => "Foo"
      public void ReadXml(XmlReader reader)
      {
        if (reader.IsEmptyElement)
        {
          Value = "";
        }
        else
        {
          reader.Read();
    
          switch (reader.NodeType)
          {
            case XmlNodeType.EndElement:
              Value = ""; // empty after all...
              break;
            case XmlNodeType.Text:
            case XmlNodeType.CDATA:
              Value = reader.ReadContentAsString();
              break;
            default:
              throw new InvalidOperationException("Expected text/cdata");
          }
        }
      }
    
      // underlying value
      public string Value { get; set; }
      public override string ToString()
      {
        return Value;
      }
    }
    
    // example usage
    [DataContract(Namespace="http://myobjects/")]
    public sealed class MyType
    {
      public string SomeValue { get; set; }
      [DataMember(Name = "SomeValue", EmitDefaultValue = false)]
      private CDataWrapper SomeValueCData
      {
        get { return SomeValue; }
        set { SomeValue = value; }
      }
    
      public string EmptyTest { get; set; }
      [DataMember(Name = "EmptyTest", EmitDefaultValue = false)]
      private CDataWrapper EmptyTestCData
      {
        get { return EmptyTest; }
        set { EmptyTest = value; }
      }
    
      public string NullTest { get; set; }
      [DataMember(Name = "NullTest", EmitDefaultValue = false)]
      private CDataWrapper NullTestCData
      {
        get { return NullTest ; }
        set { NullTest = value; }
      }
    }
    
    // test rig
    static class Program
    {
      static void Main()
      {
        DataContractSerializer dcs = new DataContractSerializer(typeof(MyType));
    
        StringWriter writer = new StringWriter();
        using (XmlWriter xw = XmlWriter.Create(writer))
        {
          MyType foo = new MyType
          {
            SomeValue = @"&<t\d",
            NullTest = null,
            EmptyTest = ""
          };
    
          ShowObject("Original", foo);
    
          dcs.WriteObject(xw, foo);
          xw.Close();
        }
    
        string xml = writer.ToString();
        ShowObject("Xml", xml);
    
        StringReader reader = new StringReader(xml);
        using (XmlReader xr = XmlReader.Create(reader))
        {
          MyType bar = (MyType) dcs.ReadObject(xr);
          ShowObject("Recreated", bar);
        }
      }
    
      static void ShowObject(string caption, object obj)
      {
        Console.WriteLine();
        Console.WriteLine("** {0} **", caption );
        Console.WriteLine();
    
        if (obj == null)
        {
          Console.WriteLine("(null)");
        }
        else if (obj is string)
        {
          Console.WriteLine((string)obj);
        }
        else
        {
          foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(obj))
          {
            Console.WriteLine("{0}:\t{1}", prop.Name, prop.GetValue(obj) ?? "(null)");
          }
        }
      }
    }
    

    【讨论】:

      【解决方案2】:

      已接受答案中 CDataWrapper 的 VB 转换:

      Imports System
      Imports System.IO
      Imports System.Runtime.Serialization
      Imports System.Xml
      Imports System.Xml.Schema
      Imports System.Xml.Serialization
      Imports System.ComponentModel
      
      Public Class CDataWrapper
          Implements IXmlSerializable
      
          'underlying value
          Public Property Value As String
      
          'Implicit to/from string
          Public Shared Widening Operator CType(ByVal value As CDataWrapper) As String
              If value Is Nothing Then
                  Return Nothing
              Else
                  Return value.Value
              End If
          End Operator
      
          Public Shared Widening Operator CType(value As String) As CDataWrapper
              If value Is Nothing Then
                  Return Nothing
              Else
                  Return New CDataWrapper() With {.Value = value}
              End If
          End Operator
      
      
          Public Function GetSchema() As XmlSchema Implements IXmlSerializable.GetSchema
              Return Nothing
          End Function
      
          ' <Node/> => ""
          ' <Node></Node> => ""
          ' <Node>Foo</Node> => "Foo"
          ' <Node><![CDATA[Foo]]></Node> => "Foo"
          Public Sub ReadXml(reader As XmlReader) Implements IXmlSerializable.ReadXml
              If reader.IsEmptyElement Then
                  Me.Value = ""
              Else
                  reader.Read()
      
                  Select Case reader.NodeType
                      Case XmlNodeType.EndElement
                          Me.Value = "" ' empty after all...
                      Case XmlNodeType.Text, XmlNodeType.CDATA
                          Me.Value = reader.ReadContentAsString()
                      Case Else
                          Throw New InvalidOperationException("Expected text/cdata")
                  End Select
              End If
          End Sub
      
          ' "" => <Node/>
          ' "Foo" => <Node><![CDATA[Foo]]></Node>
          Public Sub WriteXml(writer As XmlWriter) Implements IXmlSerializable.WriteXml
              If Not String.IsNullOrEmpty(Me.Value) Then
                  writer.WriteCData(Me.Value)
              End If
          End Sub
      
          Public Overrides Function ToString() As String
              Return Me.Value
          End Function
      End Class
      

      【讨论】:

      • 以上代码停止解析CData之后的属性。当您期望 xml 中有多个元素时,这是一个问题。在 ReadXML 的 else 标记末尾添加缺少的 reader.Read() 可解决此问题。
      【解决方案3】:

      上面的代码缺少一个事实,即您必须在阅读完内容后跳过它。所以这个类就目前而言不适用于集合。

      将其更改为以下内容,您现在可以保存 CDataWrapper 的集合。

      Value = reader.ReadContentAsString(); 
      reader.Read();
      

      【讨论】:

        【解决方案4】:

        虽然这是一个较旧的帖子,但这里是我的 2 美分。我通过将数据成员定义为 XmlElement 解决了这个问题。

         [DataMember(Name = "MyCData")]
                public XmlElement MyCDataField { get; set; }
        

        【讨论】:

          猜你喜欢
          • 2010-09-20
          • 2011-07-06
          • 2013-06-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多