2009-09-03 71 views
6

我有一個使用WCF REST入門套件的預覽版2構建的服務,但我遇到了在調用中傳遞XML樣式數據的問題。這是我的要求對象:使用CDATA和WCF REST入門套件

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

} 

一切正常,直到你把''在那裏。是否有一個將ContentText屬性封裝在CDATA或類似的東西中?

回答

11

Marc Gravell有一個用於序列化CDATA節的解決方案here

我已將這裏的代碼複製到子孫後代。

更新:前面的例子中並沒有產生一個有效的模式,在XmlSchemaProviderAttribute和相應的方法會產生「XS:字符串」其運作CDataWrapper的[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)"); 
     } 
    } 
    } 
} 
3

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 
+0

好東西。謝謝凱文! – 2011-08-11 19:54:35

+0

上面的代碼停止解析CData後的屬性。 當你期望xml中有多個元素時,這是一個問題。 在ReadXML的else標記末尾添加缺少的reader.Read()修復了此問題。 – Beejee 2014-11-06 13:03:46

3

上面的代碼缺少一個事實,即您必須在閱讀完內容後才能瀏覽內容。所以這個類現在不適用於一個集合。

將其更改爲以下內容,您現在可以保存CDataWrapper的集合。

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

儘管這是一個較舊的帖子,這裏是我的2¢。我通過將數據成員定義爲XmlElement來解決此問題。

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