【问题标题】:Can you change the XML Declaration of a WCF Client Request? If so, how?您可以更改 WCF 客户端请求的 XML 声明吗?如果是这样,怎么做?
【发布时间】:2019-12-12 09:09:28
【问题描述】:

我正在编写一个库来使用第 3 方 Web 服务(我显然无法更改)。该库当前设置为 .Net Standard 2.0,以便我可以在我当前的应用程序(.Net Framework 4.6.2)和未来可能在 .Net Core 中开发的项目中使用它。这不是必需的,但如果可能的话,我想保持这种方式。

我使用 Microsoft WCF Web Service Reference Provider 实用程序从 WSDL 生成代理类。所以我的基本客户端工厂如下所示:

public static class AuthenticationClientFactory
{
    public static AuthenticationClient CreateNew()
    {
        //Specify the binding to be used for the client.
        BasicHttpsBinding binding = new BasicHttpsBinding();

        //Specify the address to be used for the client.
        EndpointAddress address = new EndpointAddress(Globals.WebServiceAuthenticationURL);

        var client = new AuthenticationClient(binding, address);

        return client;
    }
}

在上面生成的 AuthenticationClient 上调用“AuthenticateAsync”方法时,请求创建如下:

<?xml version="1.0" encoding="utf-16"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <h:MessageId i:nil="true" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:h="http://centiro.com/facade/shared/1/0/datacontract" />
  </s:Header>
  <s:Body>
    <AuthenticateRequest xmlns:d3p1="http://schemas.datacontract.org/2004/07/Centiro.Facade.Common.Operations.Authenticate" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://centiro.com/facade/shared/1/0/servicecontract">
      <d3p1:Password>Pass123</d3p1:Password>
      <d3p1:UserName>User123</d3p1:UserName>
    </AuthenticateRequest>
  </s:Body>
</s:Envelope>

使用 SoapUI,我针对服务测试了 XML,我收到了“HTTP/1.1 400 Bad Request”。起初,我从肥皂消息中剥离了所有内容,最后将问题缩小到 XML 声明。完全剥离 XML 声明,或将声明更改为 "" 允许服务成功处理请求。

所以问题是,我如何完全剥离 XML 声明,或者更好地将声明改为“utf-8”(我通过 SoapUI 确认有效)?

我已经尝试过的事情:

  • 将 BasicHttpsBinding 上的 TextEncoding 显式更改为 utf-8。 XML 声明仍然是 utf-16。
  • 使用明确设置为 Soap11 和 utf-8 编码的 TextMessageEncodingBindingElement 创建 CustomBinding。
  • 使用 MessageInspector 使用 utf-8 重新编码消息。 (但这最终只会重新编码消息的正文)

这似乎应该是一个如此简单的改变。此时,我已准备好通过 WebClient 对象构建自己的客户端,以便更好地控制,我将自己构建对象和序列化。我在多个地方读到过,WCF 默认情况下会自动将所有内容编码为 utf-8,所以我不确定为什么声明以“utf-16”开头。

【问题讨论】:

  • 我发现这样做的唯一方法是解析像 Yitzhak 解决方案这样的字符串。解析必须至少包含 ident 行和根标记。
  • AuthenticateAuthenticateAsync 吗?如果是这样,如果你改为调用它会发生什么?
  • @dbc 不幸的是,Authenticate 和 AuthenticateAsync 方法都产生完全相同的 Soap 消息。

标签: c# xml wcf


【解决方案1】:

通常,绑定的配置已经设置了文本编码。 请尝试使用以下方式。

  IService service = factory.CreateChannel();
            using (OperationContextScope scope = new OperationContextScope((IContextChannel)service))
            {
                WebOperationContext.Current.OutgoingRequest.ContentType = "text/xml;charset=utf-8";
                service.GetData();
            }

如果我们使用代理类。

  ServiceReference1.ServiceClient client = new ServiceClient();
            using (OperationContextScope ocs=new OperationContextScope(client.InnerChannel))
{

另外,请使用客户端代理类调用服务,它应该已经封装了文本编码。
我曾经遇到过类似的问题,但我不知道解决方案是否解决了问题。希望对你有用。
如果问题仍然存在,请随时告诉我。

【讨论】:

  • 我必须将可执行文件设置为目标 .Net Framework 才能访问 WebOperationContext。一旦我这样做了,XML 声明突然消失了,但是一旦我再次针对 .Net Core,声明又回来了。不幸的是,由于声明不再针对 .Net Framework,我无法验证这是否有效。
  • 您在服务器上使用哪种安全模式?核心不支持传输带有消息凭据尾安全模式。它与 WCF 不太兼容。另外,能不能通过fiddler来捕获这个https请求(我们需要配置winhttp代理)?这有助于我们查看具体请求的内容。
【解决方案2】:

c#

void Main()
{
    XDocument xml = XDocument.Parse(@"<?xml version='1.0' encoding='utf-16'?>
                    <root>
                        <row>some text</row>
                    </root>");
    Console.WriteLine(xml.Declaration);

    XDocument doc = new XDocument(
        new XDeclaration("1.0", "utf-8", null),
        new XElement(xml.Root)
    );

    Console.WriteLine(doc.Declaration);
    Console.WriteLine(doc);
}

【讨论】:

  • LINQ to XML 让它变得简单。
  • 这可以更改 XML 消息的声明,但困难在于更改 WCF System.ServiceModel.Channels.Message 的声明。不幸的是,我认为这不像将 XML 字符串设置为实际消息那么简单。如果是,那我显然不知道在哪里做。
猜你喜欢
  • 2011-02-16
  • 1970-01-01
  • 2020-01-21
  • 2012-04-08
  • 2021-06-30
  • 1970-01-01
  • 1970-01-01
  • 2011-07-17
  • 2014-01-09
相关资源
最近更新 更多