簡體   English   中英

從 WCF 調用使用 ISO-8859-1 編碼的網絡服務

[英]Calling a webservice that uses ISO-8859-1 encoding from WCF

我正在嘗試使用 WCF 調用使用以下編碼的網絡服務:

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

我無法更改此網絡服務的編碼。 我生成了一個 wcf 代理,當我嘗試調用該代理時,出現以下錯誤:

FailedSystem.ServiceModel.ProtocolException:內容類型為text/xml; 響應消息的 charset=ISO-8859-1 與綁定的內容類型不匹配(text/xml;charset=utf-8)。 如果使用自定義編碼器,請確保正確實施 IsContentTypeSupported 方法。

有誰知道我如何使用 wcf 調用不是 UTF-8 的網絡服務?

你不能在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編碼上找到該代碼,以及基本上將整個配置包裝到代碼中的ISO88591Binding 但請注意 - 這是基於我當時的要求,例如我的服務我需要與所需的https進行通信,還有其他一些有點糟糕的設置,因此您可能需要調整它們或使它們在配置中可配置, 如果需要的話。 ISO88591Binding“項目還包含一個netHttpBinding,它再次是Microsoft提供的示例,我曾經在代碼中編寫自己的自定義綁定。

在WCF中編寫自定義綁定絕對是可能的 - 但對於膽小的人來說卻並非如此......

另一種選擇是使用較舊的.NET Framework 2.0 ASMX WebServices技術,該技術支持開箱即用的iso-8859-1

在此輸入圖像描述

在此輸入圖像描述

如果服務使用基本HTTP身份驗證,您可以像這樣指定它:

TheService theService = new TheService();
theService.Credentials = new NetworkCredential("username", "password");

在此鏈接中,您可以下載用於進行自定義綁定的文件,並在代碼中執行以下操作:

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

myWebService client = new myWebService();

client.Endpoint.Binding = binding;

如果您不想處理大量下載的代碼和低級實現,可以使用HttpWebRequest類使用舊樣式請求來解決此問題 ,如此處所述。 現在,您將免除接口的自動化代碼和工具,並將使用手動Xml解析。

我知道這是一篇舊文章,但我最近遇到了同樣的問題。 並且一些回復鏈接不再可用。

對我來說,問題是因為服務器響應 ISO-8859-1 但我的客戶端默認接受 UTF-8。

解決方案是創建一個與服務器配置匹配的 CustomTextMessageBindingElement

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;
        }
    }
}

然后創建一個使用 CustomTextMessageBindingElement 的 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);
}

最后使用 CustomBinding:

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

我相信這個解決方案應該也適用於 .net 核心,只需稍作改動並使用新的 do.net-svcutil 工具

參考:
CustomTextMessageEncodingBindingElement 的實現
消息編碼器可擴展性文檔

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM