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

vc9ivgsu  于 2023-01-27  发布在  .NET
关注(0)|答案(5)|浏览(142)

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

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

无法更改此Web服务的编码。我已生成wcf代理,但在尝试调用该代理时,收到以下错误:
FailedSystem.ServiceModel.ProtocolException:内容类型text/xml;响应消息的charset=ISO-8859-1与绑定的内容类型(text/xml;charset=utf-8)。如果使用自定义编码器,请确保正确实现IsContentTypeSupported方法。
有人知道我如何使用wcf调用不是UTF-8的Web服务吗?

svdrlsy4

svdrlsy41#

不幸的是,您不能在WCF中开箱即用。
我也遇到过同样的问题,我提出了一个你可以使用的自定义绑定(配置或代码),它基于HTTP传输,如果这对你有帮助,我可以在这里发布自定义配置,或者给你发送一个绑定的C#代码链接。
这个MSDN page here展示了如何创建一个"CustomTextEncoder",它可以支持超过UTF-8,UTF-16和Unicode编码。它包括完整的示例源代码,对我来说非常有用。
这个blog post here显示了在尝试让自定义文本编码器正常工作时需要考虑的一些附加事项。
希望能有所帮助。
马克

    • 更新日期:**

基于我上面提到的微软CustomTextEncoder示例,您可以轻松地创建一个带有ISO-8859 - 1文本消息编码的自定义绑定-只需使用以下配置片段(假设您已经下载、编译并引用了该微软示例):

<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对话,还有其他一些有点古怪的设置,所以你可能需要调整这些设置,或者让它们在config中可配置,ISO88591Binding "项目还包含一个netHttpBinding,它也是Microsoft提供的一个示例,我使用它来掌握在代码中编写自己的自定义绑定的窍门。
在WCF中编写自定义绑定绝对是可能的--但不太适合胆小的人。

lvmkulzt

lvmkulzt2#

另一种选择是使用较早的.NET Framework 2.0 ASMX WebServices技术,该技术支持开箱即用的iso-8859-1

如果服务使用基本HTTP身份验证,则可以按如下方式指定:

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

ar7v8xwq3#

link中,您可以下载用于进行自定义绑定的文件,并在代码中执行以下操作:

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

myWebService client = new myWebService();

client.Endpoint.Binding = binding;
oug3syen

oug3syen4#

如果你不想处理大量的下载代码和低级实现,你可以通过使用HttpWebRequest类的老式请求来解决,如here所述。现在,你将免除自动化代码和接口的设施,并将使用手动Xml解析。

8ulbf1ek

8ulbf1ek5#

我知道这是一个老职位,但我最近面临同样的问题。和一些回应链接不再可用。
对我来说,这个问题是因为服务器使用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的自定义绑定:

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

最后使用自定义绑定:

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

我相信,解决方案只需稍加更改并使用新的dotnet-svcutil工具,也应该适用于.net core
参考文献:
Implementation of CustomTextMessageEncodingBindingElement
Docs for Message Encoder Extensibility

相关问题