c# - 配置 .NET WCF UTF-8 反序列化器以修改/丢弃非最短格式字符而不是抛出异常?

标签 c# wcf serialization utf-8

我们有一个通过 WCF 托管的 SOAP 网络服务。

我们偶尔从其中接收数据的客户端之一使用非最短格式对 UTF-8 进行编码(有关这方面的一些信息,请参阅 http://www.unicode.org/versions/corrigendum1.html)。

修改客户端并不容易,因为我们的代码没有对这些非最短形式的字符进行编码。

相反,我们希望编辑 WCF 服务以丢弃这些字符,将它们替换为其他占位符字符,甚至接受非最短形式的字符。对于我们的用例,这些中的任何一个都是可以接受的,尽管前一个选项是首选,因为它们减少了任何安全风险。

查看堆栈跟踪:

System.ServiceModel.Dispatcher.NetDispatcherFaultException: The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://www.mydomain.com/:mytype. The InnerException message was 'There was an error deserializing the object of type MyNamespace.MyType`1[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c461934e089]]. '????' contains invalid UTF8 bytes.'.  Please see InnerException for more details. ---> System.Runtime.Serialization.SerializationException: There was an error deserializing the object of type MyNamespace.MyType`1[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c461934e089]]. '????' contains invalid UTF8 bytes. ---> System.Xml.XmlException: '????' contains invalid UTF8 bytes. ---> System.Text.DecoderFallbackException: Unable to translate bytes [C0] at index 0 from specified code page to Unicode.
   at System.Text.DecoderExceptionFallbackBuffer.Throw(Byte[] bytesUnknown, Int32 index)
   at System.Text.DecoderExceptionFallbackBuffer.Fallback(Byte[] bytesUnknown, Int32 index)
   at System.Text.DecoderFallbackBuffer.InternalFallback(Byte[] bytes, Byte* pBytes, Char*& chars)
   at System.Text.UTF8Encoding.FallbackInvalidByteSequence(Byte*& pSrc, Int32 ch, DecoderFallbackBuffer fallback, Char*& pTarget)
   at System.Text.UTF8Encoding.GetChars(Byte* bytes, Int32 byteCount, Char* chars, Int32 charCount, DecoderNLS baseDecoder)
   at System.Text.UTF8Encoding.GetChars(Byte[] bytes, Int32 byteIndex, Int32 byteCount, Char[] chars, Int32 charIndex)
   at System.Xml.XmlConverter.ToChars(Byte[] buffer, Int32 offset, Int32 count, Char[] chars, Int32 charOffset)
   --- End of inner exception stack trace ---
   at System.Xml.XmlConverter.ToChars(Byte[] buffer, Int32 offset, Int32 count, Char[] chars, Int32 charOffset)
   at System.Xml.XmlBufferReader.GetChars(Int32 offset, Int32 length, Char[] chars)
   at System.Xml.ValueHandle.GetCharsText()
   at System.Xml.ValueHandle.GetString()
   at System.Xml.XmlBaseReader.get_Value()
   at System.Xml.XmlDictionaryReader.ReadContentAsString(Int32 maxStringContentLength)
   at System.Xml.XmlBaseReader.ReadContentAsString()
   at System.Xml.XmlBaseReader.ReadElementContentAsString()
   at System.Runtime.Serialization.XmlReaderDelegator.ReadElementContentAsString()
   at ReadOrbliteCompatibleArrayOfstringFromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString , XmlDictionaryString , CollectionDataContract )
   at System.Runtime.Serialization.CollectionDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)
   at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, DataContract& dataContract)
   at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, DataContract dataContract, String name, String ns)
   at System.Runtime.Serialization.DataContractSerializer.InternalReadObject(XmlReaderDelegator xmlReader, Boolean verifyObjectName)
   at System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator reader, Boolean verifyObjectName)
   --- End of inner exception stack trace ---
   at System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator reader, Boolean verifyObjectName)
   at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.DeserializeParameterPart(XmlDictionaryReader reader, PartInfo part, Boolean isRequest)
   --- End of inner exception stack trace ---
   at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.DeserializeParameterPart(XmlDictionaryReader reader, PartInfo part, Boolean isRequest)
   at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.DeserializeParameters(XmlDictionaryReader reader, PartInfo[] parts, Object[] parameters, Boolean isRequest)
   at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.DeserializeBody(XmlDictionaryReader reader, MessageVersion version, String action, MessageDescription messageDescription, Object[] parameters, Boolean isRequest)
   at System.ServiceModel.Dispatcher.OperationFormatter.DeserializeBodyContents(Message message, Object[] parameters, Boolean isRequest)
   at System.ServiceModel.Dispatcher.OperationFormatter.DeserializeRequest(Message message, Object[] parameters)
   at System.ServiceModel.Dispatcher.DispatchOperationRuntime.DeserializeInputs(MessageRpc& rpc)
   at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc& rpc)
   at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)

看起来我们想要的是将解码器回退从 System.Text.DecoderExceptionFallback 切换到 System.Text.DecoderReplacementFallback

有人可以指出正确的位置和方法来使用替代回退覆盖默认异常回退吗?

最佳答案

探索的一种可能性是创建自定义编码器。看看http://msdn.microsoft.com/en-us/library/ms751486.aspx


由劳伦斯·约翰斯顿添加:

这是我最终使用的代码的主要部分。我的 MessageEncoder 子类只是包装了一个 MessageEncoder 实例,并将除对 ReadMessage 的调用之外的所有调用传递给包装的类。

public override Message ReadMessage(ArraySegment<Byte> buffer, BufferManager bufferManager, String contentType) {
    // Convert buffer to stream and pass to overload.
    byte[] msgContents = new byte[buffer.Count];
    Array.Copy(buffer.Array, buffer.Offset, msgContents, 0, msgContents.Length);
    bufferManager.ReturnBuffer(buffer.Array);

    MemoryStream stream = new MemoryStream(msgContents);
    return ReadMessage(stream, int.MaxValue);
}

public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType) {
    // The only new functionality in this class is to pass the stream through a 
    // StreamReader with the encoding set to *not* throw on invalid bytes. 
    XmlReader reader = XmlReader.Create(new StreamReader(stream, new UTF8Encoding(false, false)));
    return Message.CreateMessage(reader, maxSizeOfHeaders, MessageVersion);
}

关于c# - 配置 .NET WCF UTF-8 反序列化器以修改/丢弃非最短格式字符而不是抛出异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4270256/

相关文章:

c# - 如何以 xamarin 形式动态更改 CultureInfo

c# - 使用 iText 7 for .NET 时如何定义 Colspan 和 Rowspan

c# - WPF TimeSpan 绑定(bind)到没有毫秒的标签

wcf - Delphi 客户端使用的 WCF 中生成的 WSDL

java - 使用 Turnkey Linux 在 Windows 环境中托管 Java Web 服务?

c++ - 将整数打包/解包到 char* 或从 char* 打包/解包时出现问题

c# - 哪个是 C# 和 .NET 的 "best"数据访问框架/方法?

WCF 错误 : A registration already exists for URI

multithreading - 使用来自 wicket 的工作线程时如何处理序列化?

java - Spring中如何通过CrudRepository的 `findAll()`方法在序列化中包含回收对象的id?