从 WCF 调用使用 ISO-8859-1 编码的 Web 服务

问题描述 投票:0回答:6

我正在尝试使用 WCF 调用使用以下编码的 Web 服务:

<?xml version="1.0" encoding="ISO-8859-1" ?> 

我无法更改此网络服务的编码。 我已经生成了一个 wcf 代理,当我尝试调用该代理时,出现以下错误:

FailedSystem.ServiceModel.ProtocolException: 内容类型text/xml; 响应的 charset=ISO-8859-1 消息与内容不符 绑定的类型(text/xml; 字符集=utf-8)。如果使用自定义 编码器,请确保 IsContentTypeSupported 方法是 正确实施。

有人知道如何使用 wcf 调用非 UTF-8 的 Web 服务吗?

.net wcf
6个回答
24
投票

不幸的是,您无法在 WCF 中开箱即用地执行此操作。

我遇到了同样的问题,并提出了一个可以使用的自定义绑定(在配置或代码中)。它基于 HTTP 传输,如果这对您有帮助,我可以在此处发布自定义配置,或向您发送指向绑定的 C# 代码的链接。

这个 MSDN 页面在这里展示了如何创建一个“CustomTextEncoder”,它可以支持超过 utf-8、utf-16 和 unicode 编码。它包含完整的示例源代码,对我的工作非常有用。

这篇博客文章显示了在尝试让自定义文本编码器正常工作时需要考虑的一些其他事项。

希望有帮助。

马克

更新:
基于我上面提到的 CustomTextEncoder 的 Microsoft 示例,您可以轻松创建具有 ISO-8859-1 文本消息编码的自定义绑定 - 只需使用此配置片段(假设您已下载并编译并引用该 Microsoft 示例):

  <system.serviceModel>
    <extensions>
      <bindingElementExtensions>
        <add name="customTextMessageEncoding"
             type="Microsoft.ServiceModel.Samples.CustomTextMessageEncodingElement, 
                   Microsoft.ServiceModel.Samples.CustomTextEncoder"/>
      </bindingElementExtensions>
    </extensions>
    <bindings>
      <customBinding>
        <binding name="ISO8859Binding" >
          <customTextMessageEncoding encoding="ISO-8859-1" />
          <httpTransport />
        </binding>
      </customBinding>
    </bindings>

    <client>
      <endpoint name="Test"
                address="......."
                binding="customBinding"
                bindingConfiguration="ISO8859Binding" 
                contract="IYourContract" />
    </client>
  </system.serviceModel>

您可以在我的 Skydrive 目录

WCF ISO 8859-1 Encoding
上找到该代码,以及基本上将整个配置包装成代码的 ISO88591Binding。但请注意 - 这是基于我当时的要求,例如我的服务需要与所需的 https 进行通信,以及其他一些有点奇怪的设置,因此您可能需要调整这些设置或使它们在配置中可配置(如果需要)。该 ISO88591Binding”项目还包含一个 netHttpBinding,它也是 Microsoft 提供的示例,我用它来掌握在代码中编写自己的自定义绑定的技巧。

在 WCF 中编写自定义绑定绝对是可能的 - 但对于胆小的人来说则不然......


9
投票

另一种选择是使用较旧的 .NET Framework 2.0 ASMX WebServices 技术,该技术支持开箱即用:


enter image description here

enter image description here 如果服务使用基本 HTTP 身份验证,您可以这样指定:

iso-8859-1



7
投票
链接

中,您可以下载用于进行自定义绑定的文件,并在代码中执行以下操作: TheService theService = new TheService(); theService.Credentials = new NetworkCredential("username", "password");



3
投票
此处

所述。现在,您将免除接口的自动化代码和工具,并使用手动 Xml 解析。


3
投票

对我来说,问题是因为服务器响应 ISO-8859-1 但我的客户端默认接受 UTF-8 引起的。

解决方案是创建一个与服务器配置匹配的 CustomTextMessageBindingElement

: CustomBinding binding = new CustomBinding( new CustomTextMessageBindingElement("iso-8859-1", "text/xml", MessageVersion.Soap11), new HttpTransportBindingElement()); myWebService client = new myWebService(); client.Endpoint.Binding = binding;

然后创建一个使用 CustomTextMessageBindingElement 的 CustomBinding:

public class CustomTextMessageBindingElement : MessageEncodingBindingElement { public override MessageVersion MessageVersion { get; set; } public string MediaType { get; set; } public string Encoding { get; set; } CustomTextMessageBindingElement(CustomTextMessageBindingElement binding) : this(binding.Encoding, binding.MediaType, binding.MessageVersion) { } public CustomTextMessageBindingElement(string encoding, string mediaType, MessageVersion messageVersion) { this.MessageVersion = messageVersion; this.MediaType = mediaType; this.Encoding = encoding; } public CustomTextMessageBindingElement(string encoding, MessageVersion messageVersion) { this.Encoding = encoding; this.MessageVersion = messageVersion; if (messageVersion.Envelope == EnvelopeVersion.Soap11) { this.MediaType = "text/xml"; } else if (messageVersion.Envelope == EnvelopeVersion.Soap12) { this.MediaType = "application/soap+xml"; } else { this.MediaType = "application/xml"; } } public override BindingElement Clone() { return new CustomTextMessageBindingElement(this); } public override MessageEncoderFactory CreateMessageEncoderFactory() { return new CustomTextMessageEncoderFactory(MediaType, Encoding, MessageVersion); } public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context) { if (context == null) { throw new ArgumentNullException("context"); } context.BindingParameters.Add(this); return context.BuildInnerChannelFactory<TChannel>(); } } 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 bool IsContentTypeSupported(string contentType) { return true; } 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; } } }

最后使用 CustomBinding:

private Binding GetBindConfiguration() { //This configs could be different in Soap server that you are implementing //set the soap server config: encoding, mediaType and Soap Version 1.1 var custom = new CustomTextMessageBindingElement("ISO-8859-1", "text/xml", MessageVersion.CreateVersion(EnvelopeVersion.Soap11, AddressingVersion.None)); var httpsBindingElement = new HttpsTransportBindingElement() { MaxReceivedMessageSize = int.MaxValue, }; return new CustomBinding(custom, httpsBindingElement); }

我相信
这个

解决方案,也应该适用于.net core,只需进行很少的更改并使用新的 dotnet-svcutil 工具 参考资料:

CustomTextMessageEncodingBindingElement 的实现
消息编码器扩展性文档


0
投票

//Auto generated class using svcutil tool var clientSoap = new WebService_SigISSPortTypeClient(GetBindConfiguration(), new EndpointAddress(new Uri("https://serverAddress.com.br")));

对于自定义短信,我从
这里

获取了类文件

© www.soinside.com 2019 - 2024. All rights reserved.