Вот мой обходной код.Я не очень доволен этим;это не покрывает все случаи (хотя это заботится о моих потребностях), и кажется, что должно быть более простое решение.Я опубликую его здесь с надеждой, что кто-то еще может сделать его лучше или что у кого-то есть более простой ответ.
Чтобы обойти эту проблему, я создал новый атрибут поведения операции, чтобы изменить сериализатор на пользовательскийСериализатор, который удаляет символы, которые будут отображаться как недопустимые объекты XML:
public class StripInvalidXmlCharactersBehaviorAttribute
: Attribute, IOperationBehavior
{
public void AddBindingParameters(
OperationDescription operationDescription,
BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(
OperationDescription operationDescription,
ClientOperation clientOperation)
{
IOperationBehavior behavior =
new StripInvalidXmlCharactersBehavior(operationDescription);
behavior.ApplyClientBehavior(operationDescription, clientOperation);
}
public void ApplyDispatchBehavior(
OperationDescription operationDescription,
DispatchOperation dispatchOperation)
{
IOperationBehavior behavior =
new StripInvalidXmlCharactersBehavior(operationDescription);
behavior.ApplyDispatchBehavior(
operationDescription, dispatchOperation);
}
public void Validate(OperationDescription operationDescription)
{
}
}
Само поведение выглядит так:
internal class StripInvalidXmlCharactersBehavior
: DataContractSerializerOperationBehavior
{
public StripInvalidXmlCharactersBehavior(OperationDescription opDesc)
: base(opDesc)
{
}
public override XmlObjectSerializer CreateSerializer(
Type type, string name, string ns, IList<Type> knownTypes)
{
return new InvalidXmlStrippingSerializer(type, name, ns, knownTypes);
}
public override XmlObjectSerializer CreateSerializer(
Type type, XmlDictionaryString name, XmlDictionaryString ns,
IList<Type> knownTypes)
{
return new InvalidXmlStrippingSerializer(type, name, ns, knownTypes);
}
}
И это сериализатор:
internal class InvalidXmlStrippingSerializer : XmlObjectSerializer
{
private DataContractSerializer _innerSerializer;
public InvalidXmlStrippingSerializer(
Type type, string name, string ns, IList<Type> knownTypes)
{
_innerSerializer =
new DataContractSerializer(type, name, ns, knownTypes);
}
public InvalidXmlStrippingSerializer(
Type type, XmlDictionaryString name, XmlDictionaryString ns,
IList<Type> knownTypes)
{
_innerSerializer =
new DataContractSerializer(type, name, ns, knownTypes);
}
public override bool IsStartObject(XmlDictionaryReader reader)
{
return _innerSerializer.IsStartObject(reader);
}
public override object ReadObject(
XmlDictionaryReader reader, bool verifyObjectName)
{
return _innerSerializer.ReadObject(reader, verifyObjectName);
}
public override void WriteEndObject(XmlDictionaryWriter writer)
{
_innerSerializer.WriteEndObject(writer);
}
public override void WriteObjectContent(
XmlDictionaryWriter writer, object graph)
{
graph = fixBadStringsRecursive(graph);
_innerSerializer.WriteObjectContent(writer, graph);
}
private object fixBadStringsRecursive(object graph)
{
var objType = graph.GetType();
if (objType == typeof(string))
{
graph = removeInvalidCharacters(graph as string);
}
else if (graph is IEnumerable)
{
foreach (var item in graph as IEnumerable)
{
fixBadStringsRecursive(item);
}
}
else if (objType.IsClass)
{
// Look through the properties of the object
foreach (var prop in graph.GetType().GetProperties())
{
var propParams = prop.GetIndexParameters();
if ((propParams == null || propParams.Length == 0)
&& prop.GetGetMethod() != null)
{
var propVal = prop.GetValue(graph, null);
if (propVal != null)
{
propVal = fixBadStringsRecursive(propVal);
if (prop.GetSetMethod() != null)
{
prop.SetValue(graph, propVal, null);
}
}
}
}
}
return graph;
}
private static string removeInvalidCharacters(string source)
{
// This is per the W3C XML spec:
// http://www.w3.org/TR/xml/#NT-Char
return new string(
(
from ch in source
where
ch == '\u0009' || ch == '\u000a' || ch == '\u000d'
|| (ch >= '\u0020' && ch <= '\ud7ff')
|| (ch >= '\ue000' && ch <= '\ufffd')
select ch
).ToArray()
);
}
public override void WriteStartObject(
XmlDictionaryWriter writer, object graph)
{
_innerSerializer.WriteStartObject(writer, graph);
}
}
Чтобы применить поведение к моей операции, теперь я могу просто добавить созданный мной атрибут.