【问题标题】:Using ISO-8859-1 encoding between WCF and Oracle/Linux在 WCF 和 Oracle/Linux 之间使用 ISO-8859-1 编码
【发布时间】:2011-08-11 22:01:05
【问题描述】:

我有一个 WCF 服务,它可以发送/接收数据并与我所有的 utf-8 客户端完美配合。

但是,我的一位客户正在尝试使用 Oracle 9i/Linux 调用访问此服务,该调用使用 ISO-8859-1 编码,但我们遇到了特殊字符问题。

我不能使用this建议的解决方案,因为客户端是Linux,无法安装DLL。

基于这种情况,谁能建议我另一种解决方案(这可能涉及客户端、服务或两者的更改)?

提前致谢。

【问题讨论】:

    标签: wcf oracle utf-8 iso-8859-1


    【解决方案1】:

    该解决方案(使用 CustomTextEncoder)是否也适用于您的场景? linux 客户端可以继续发送它喜欢的数据(即,在 iso-8859-1 中),并且仅在服务器上使用的编码器将能够读取它。然后编码器可以决定如何将响应编码回客户端(UTF-8 或 iso-8859-1)。

    如果您还希望响应采用 iso-8859-1 格式,您可能还需要消息检查器之类的东西来使用适当的字符集更新内容类型标头。

    更新:使用 ISO-8859-1 的自定义编码器示例

    public class StackOverflow_7033442
    {
        [ServiceContract]
        public interface ITest
        {
            [OperationContract]
            string Echo(string text);
        }
    
        public class Service : ITest
        {
            public string Echo(string text)
            {
                return text;
            }
        }
    
        public static void Test()
        {
            string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
            ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
            CustomBinding binding = new CustomBinding(
                new CustomTextMessageBindingElement("iso-8859-1", "text/xml", MessageVersion.Soap11),
                new HttpTransportBindingElement());
            host.AddServiceEndpoint(typeof(ITest), binding, "");
            host.Open();
            Console.WriteLine("Host opened");
    
            string request = @"<?xml version=""1.0"" encoding=""iso-8859-1""?>
    <s:Envelope xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/"">
      <s:Body>
        <Echo xmlns=""http://tempuri.org/"">
          <text>Hello áéíóú</text>
        </Echo>
      </s:Body>
    </s:Envelope>";
            HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(baseAddress);
            req.Method = "POST";
            req.ContentType = "text/xml; charset=iso-8859-1";
            req.Headers["SOAPAction"] = "http://tempuri.org/ITest/Echo";
            Stream reqStream = req.GetRequestStream();
            Encoding encoding = Encoding.GetEncoding("iso-8859-1");
            byte[] reqBytes = encoding.GetBytes(request);
            reqStream.Write(reqBytes, 0, reqBytes.Length);
            reqStream.Close();
    
            HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
            Console.WriteLine("HTTP/{0} {1} {2}", resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription);
            foreach (var header in resp.Headers.AllKeys)
            {
                Console.WriteLine("{0}: {1}", header, resp.Headers[header]);
            }
    
            if (resp.ContentLength > 0)
            {
                Console.WriteLine(new StreamReader(resp.GetResponseStream(), encoding).ReadToEnd());
            }
    
            Console.Write("Press ENTER to close the host");
            Console.ReadLine();
            host.Close();
        }
    
        #region Custom Text Message Encoder sample, verbatim
        public class CustomTextMessageEncoder : MessageEncoder
        {
            private CustomTextMessageEncoderFactory factory;
            private XmlWriterSettings writerSettings;
            private string contentType;
    
            public CustomTextMessageEncoder(CustomTextMessageEncoderFactory factory)
            {
                this.factory = factory;
    
                this.writerSettings = new XmlWriterSettings();
                this.writerSettings.Encoding = Encoding.GetEncoding(factory.CharSet);
                this.contentType = string.Format("{0}; charset={1}",
                    this.factory.MediaType, this.writerSettings.Encoding.HeaderName);
            }
    
            public override string ContentType
            {
                get
                {
                    return this.contentType;
                }
            }
    
            public override string MediaType
            {
                get
                {
                    return factory.MediaType;
                }
            }
    
            public override MessageVersion MessageVersion
            {
                get
                {
                    return this.factory.MessageVersion;
                }
            }
    
            public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
            {
                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)
            {
                XmlReader reader = XmlReader.Create(stream);
                return Message.CreateMessage(reader, maxSizeOfHeaders, this.MessageVersion);
            }
    
            public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
            {
                MemoryStream stream = new MemoryStream();
                XmlWriter writer = XmlWriter.Create(stream, this.writerSettings);
                message.WriteMessage(writer);
                writer.Close();
    
                byte[] messageBytes = stream.GetBuffer();
                int messageLength = (int)stream.Position;
                stream.Close();
    
                int totalLength = messageLength + messageOffset;
                byte[] totalBytes = bufferManager.TakeBuffer(totalLength);
                Array.Copy(messageBytes, 0, totalBytes, messageOffset, messageLength);
    
                ArraySegment<byte> byteArray = new ArraySegment<byte>(totalBytes, messageOffset, messageLength);
                return byteArray;
            }
    
            public override void WriteMessage(Message message, Stream stream)
            {
                XmlWriter writer = XmlWriter.Create(stream, this.writerSettings);
                message.WriteMessage(writer);
                writer.Close();
            }
        }
        public class CustomTextMessageEncoderFactory : MessageEncoderFactory
        {
            private MessageEncoder encoder;
            private MessageVersion version;
            private string mediaType;
            private string charSet;
    
            internal CustomTextMessageEncoderFactory(string mediaType, string charSet,
                MessageVersion version)
            {
                this.version = version;
                this.mediaType = mediaType;
                this.charSet = charSet;
                this.encoder = new CustomTextMessageEncoder(this);
            }
    
            public override MessageEncoder Encoder
            {
                get
                {
                    return this.encoder;
                }
            }
    
            public override MessageVersion MessageVersion
            {
                get
                {
                    return this.version;
                }
            }
    
            internal string MediaType
            {
                get
                {
                    return this.mediaType;
                }
            }
    
            internal string CharSet
            {
                get
                {
                    return this.charSet;
                }
            }
        }
        public class CustomTextMessageBindingElement : MessageEncodingBindingElement, IWsdlExportExtension
        {
            private MessageVersion msgVersion;
            private string mediaType;
            private string encoding;
            private XmlDictionaryReaderQuotas readerQuotas;
    
            CustomTextMessageBindingElement(CustomTextMessageBindingElement binding)
                : this(binding.Encoding, binding.MediaType, binding.MessageVersion)
            {
                this.readerQuotas = new XmlDictionaryReaderQuotas();
                binding.ReaderQuotas.CopyTo(this.readerQuotas);
            }
    
            public CustomTextMessageBindingElement(string encoding, string mediaType,
                MessageVersion msgVersion)
            {
                if (encoding == null)
                    throw new ArgumentNullException("encoding");
    
                if (mediaType == null)
                    throw new ArgumentNullException("mediaType");
    
                if (msgVersion == null)
                    throw new ArgumentNullException("msgVersion");
    
                this.msgVersion = msgVersion;
                this.mediaType = mediaType;
                this.encoding = encoding;
                this.readerQuotas = new XmlDictionaryReaderQuotas();
            }
    
            public CustomTextMessageBindingElement(string encoding, string mediaType)
                : this(encoding, mediaType, MessageVersion.Soap11WSAddressing10)
            {
            }
    
            public CustomTextMessageBindingElement(string encoding)
                : this(encoding, "text/xml")
            {
    
            }
    
            public CustomTextMessageBindingElement()
                : this("UTF-8")
            {
            }
    
            public override MessageVersion MessageVersion
            {
                get
                {
                    return this.msgVersion;
                }
    
                set
                {
                    if (value == null)
                        throw new ArgumentNullException("value");
                    this.msgVersion = value;
                }
            }
    
    
            public string MediaType
            {
                get
                {
                    return this.mediaType;
                }
    
                set
                {
                    if (value == null)
                        throw new ArgumentNullException("value");
                    this.mediaType = value;
                }
            }
    
            public string Encoding
            {
                get
                {
                    return this.encoding;
                }
    
                set
                {
                    if (value == null)
                        throw new ArgumentNullException("value");
                    this.encoding = value;
                }
            }
    
            // This encoder does not enforces any quotas for the unsecure messages. The 
            // quotas are enforced for the secure portions of messages when this encoder
            // is used in a binding that is configured with security. 
            public XmlDictionaryReaderQuotas ReaderQuotas
            {
                get
                {
                    return this.readerQuotas;
                }
            }
    
            #region IMessageEncodingBindingElement Members
    
            public override MessageEncoderFactory CreateMessageEncoderFactory()
            {
                return new CustomTextMessageEncoderFactory(this.MediaType,
                    this.Encoding, this.MessageVersion);
            }
    
            #endregion
    
    
            public override BindingElement Clone()
            {
                return new CustomTextMessageBindingElement(this);
            }
    
            public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
            {
                if (context == null)
                    throw new ArgumentNullException("context");
    
                context.BindingParameters.Add(this);
                return context.BuildInnerChannelFactory<TChannel>();
            }
    
            public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
            {
                if (context == null)
                    throw new ArgumentNullException("context");
    
                return context.CanBuildInnerChannelFactory<TChannel>();
            }
    
            public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
            {
                if (context == null)
                    throw new ArgumentNullException("context");
    
                context.BindingParameters.Add(this);
                return context.BuildInnerChannelListener<TChannel>();
            }
    
            public override bool CanBuildChannelListener<TChannel>(BindingContext context)
            {
                if (context == null)
                    throw new ArgumentNullException("context");
    
                context.BindingParameters.Add(this);
                return context.CanBuildInnerChannelListener<TChannel>();
            }
    
            public override T GetProperty<T>(BindingContext context)
            {
                if (typeof(T) == typeof(XmlDictionaryReaderQuotas))
                {
                    return (T)(object)this.readerQuotas;
                }
                else
                {
                    return base.GetProperty<T>(context);
                }
            }
    
            #region IWsdlExportExtension Members
    
            void IWsdlExportExtension.ExportContract(WsdlExporter exporter, WsdlContractConversionContext context)
            {
            }
    
            void IWsdlExportExtension.ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context)
            {
                // The MessageEncodingBindingElement is responsible for ensuring that the WSDL has the correct
                // SOAP version. We can delegate to the WCF implementation of TextMessageEncodingBindingElement for this.
                TextMessageEncodingBindingElement mebe = new TextMessageEncodingBindingElement();
                mebe.MessageVersion = this.msgVersion;
                ((IWsdlExportExtension)mebe).ExportEndpoint(exporter, context);
            }
    
            #endregion
        }
        #endregion
    }
    

    【讨论】:

    • 我已经用示例更新了答案,其中编码器是示例中的确切类(我什至没有更改单个字符)。您必须确保传递给CustomTextMessageBindingElement 的参数与您拥有的绑定兼容。
    猜你喜欢
    • 2011-06-10
    • 2011-02-12
    • 2011-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-06
    • 1970-01-01
    相关资源
    最近更新 更多