我使用WCF REST入门套件的预览2构建了一个服务,但是我遇到了在调用中传递XML样式数据的问题。这是我的请求对象:
[DataContract(Namespace = "")]
public class ServiceRequest
{
[DataMember]
public string ContentText { get; set; }
[DataMember]
public string ApiKey { get; set; }
}
一切正常,直到你扔在那里。有没有将ContentText属性封装在CDATA或类似的东西中?
答案 0 :(得分:12)
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)");
}
}
}
}
答案 1 :(得分:3)
在接受的答案中对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
答案 2 :(得分:3)
以上代码遗漏了您在阅读完内容后必须浏览的内容。因此,这个类不适用于集合。
将其更改为以下内容,您现在可以保留CDataWrapper
的集合。
Value = reader.ReadContentAsString();
reader.Read();
答案 3 :(得分:0)
虽然这是一个较旧的帖子,但这里是我的2¢。我通过将数据成员定义为XmlElement来解决此问题。
[DataMember(Name = "MyCData")]
public XmlElement MyCDataField { get; set; }