C# 如何修改WCF消息头&x27;s必须了解如何使用ClientInspector

C# 如何修改WCF消息头&x27;s必须了解如何使用ClientInspector,c#,.net,wcf,web-services,soap,C#,.net,Wcf,Web Services,Soap,我正在从WCF客户端调用非WCF服务。WCF客户端包括设置为“1”的“MustUnderstand”头属性。下面是一个典型的SOAP请求: <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <s:Header>

我正在从WCF客户端调用非WCF服务。WCF客户端包括设置为“1”的“MustUnderstand”头属性。下面是一个典型的SOAP请求:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<s:Header>
    <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
        <u:Timestamp u:Id="_0">
            <u:Created>2010-08-23T20:48:52.680Z</u:Created>
            <u:Expires>2010-08-23T20:53:52.680Z</u:Expires>
        </u:Timestamp>
        <o:UsernameToken u:Id="uuid-72ea0c0a-43aa-43b2-bed7-c2da13624105-1">
            <o:Username>blablabla</o:Username>
            <o:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">blablabla</o:Password>
        </o:UsernameToken>
    </o:Security>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <HeartbeatRequest xmlns="http://removed">
        <DateTime xmlns="">8/23/2010 4:48:51 PM</DateTime>
        <Message xmlns="">123</Message>
    </HeartbeatRequest>
</s:Body>
现在是实际检查员:

    public class ExInspector : IClientMessageInspector
{

    #region IClientMessageInspector Members

    public void AfterReceiveReply(ref Message reply, object correlationState)
    {
        // no op
        return;
    }

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        MessageBuffer buffer = request.CreateBufferedCopy(int.MaxValue);

        Message newMessage = buffer.CreateMessage();

        newMessage.Headers.RemoveAt(0);

        newMessage.Headers.Add(MessageHeader.CreateHeader
            (
                request.Headers[0].Name,
                request.Headers[0].Namespace,
                string.Empty,
                false,
                string.Empty,
                request.Headers[0].Relay
            )
        );

        request = newMessage;

        return null;
    }

    #endregion
}
如您所见,我正在通过缓冲副本创建一个新请求,然后删除安全标头(只有一个标头)并添加一个MustUnderstand设置为false的新标头(为什么要这样做?MessageHeader.MustUnderstand是只读的)。我在这个方法中设置了一个断点,实际上,新的头被添加了,新消息被写回请求,并且newMessage.Headers[0].MustUnderstand和request.Headers[0].MustUnderstand在这个方法的末尾都是false

但是,发送到服务的消息标题上仍然包含MustUnderstand=“1”

以下是包含上述行为的app.config:

<configuration>
<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="WebServiceSOAP" closeTimeout="00:01:00" openTimeout="00:01:00"
                    receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
                    bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                    maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
                    useDefaultWebProxy="true">
                <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                <security mode="TransportWithMessageCredential">
                    <transport clientCredentialType="Basic" proxyCredentialType="None" realm="" />
                    <message clientCredentialType="UserName" algorithmSuite="Default" />
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint
                address="https://removed"
                behaviorConfiguration="ovrExClientBehavior"
                binding="basicHttpBinding"
                bindingConfiguration="WebServiceSOAP"
                contract="EWebService.EWebService"
                name="WebServiceSOAP" />
    </client>
    <extensions>
        <behaviorExtensions>
            <add name="exClientBehavior" type="ExMessageInspector.ExClientBehaviorExtensionElement, ExMessageInspector, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
        </behaviorExtensions>
    </extensions>
    <behaviors>
        <endpointBehaviors>
            <behavior name="ovrExClientBehavior">
                <exClientBehavior />
            </behavior>
        </endpointBehaviors>
    </behaviors>
</system.serviceModel>

所以我的问题是:有没有可能像上面那样在发送的消息上更改MustUnderstand,或者以类似的方式更改MustUnderstand?还是在检查器替换安全标头之后,在管道中强制将其更改回true

注意:服务所有者说,他们只知道另一个组织在.NET中使用此服务,并且该消费者必须基本上抛弃WCF和WSE,从头开始创建SOAP消息并处理回复,可能使用POX帖子或类似的方式。我们确实希望避免这种情况,因为我们需要调用服务上的许多操作

此外,我们还需要保持消息的主体和属性完好无损


任何帮助都将不胜感激

我想知道,如果供应商不遵循互操作性标准,为什么会存在互操作性标准。若客户端检查器不起作用,你们可以尝试实现自定义消息编码器并修改那个里的头

编辑:

这里的问题是,如果您同时声明服务不必理解带有credentials=的标头,并且不必使用它们,那么为什么要发送用户凭据进行身份验证。你真的需要它们吗

根据您的需求,还有其他方法。你需要时间戳吗?是否在服务器上检查了时间戳?所有通话都有单一用户,还是通话之间必须有不同的用户

如果您不需要时间戳或未检查时间戳,并且您只有一个用户名和密码,最简单的方法是不使用TransportWithMessageCredential安全模式。改为使用纯传输,并将标题描述放在客户端端点配置中,如:

<client>
   <endpoint address="https://removed" binding="basicHttpBinding" bindingConfiguration="WebServiceSOPA" contract="EWebService.EWebService" name="WebServiceSOAP">
    <headers>
     <wsse:Security s:mustUnderstand="0" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
      <wsse:UsernameToken wsu:Id="SecurityToken-3f7f983f-66ce-480d-bce6-170632d33f92" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
       <wsse:Username>User</wsse:Username>
       <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">Pwd123</wsse:Password>
      </wsse:UsernameToken>
     </wsse:Security>
    </headers>
   </endpoint>
  </client>

使用者
Pwd123

如果您有多个用户名,或者如果您需要实际数据的真实时间戳,您可以使用相同的方法,但可以在代码中创建自定义头,避免WCF安全性,而不是静态配置。这可以使用message inspector来完成。

很遗憾,是的,此供应商将MustUnderstand=0与仍然在标题中强制使用(静态)用户名/密码相结合。如果我们忽略了这一点,我们将返回一个缺少actor(即缺少元素)的错误。我认为不需要时间戳。嗯-我将尝试端点配置方法并进行回复。好的,谢谢Ladislav!我尝试了你的方法,因为我们“幸运”拥有一个静态用户名/密码,使用Transport仅是为了安全,并且在你设置静态标题时使用它-很有效!!非常感谢。拉迪斯拉夫,谢谢你的方法,但我不能用它。当我在端点配置中添加此头时,出现编译错误
s:未定义前缀
。能否请您对此标题中应使用的名称空间发表评论。在代码示例中,它似乎绑定到xmlns:s=“”谢谢,我已经尝试解决此问题一段时间了。
<configuration>
<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="WebServiceSOAP" closeTimeout="00:01:00" openTimeout="00:01:00"
                    receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
                    bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                    maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
                    useDefaultWebProxy="true">
                <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                <security mode="TransportWithMessageCredential">
                    <transport clientCredentialType="Basic" proxyCredentialType="None" realm="" />
                    <message clientCredentialType="UserName" algorithmSuite="Default" />
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint
                address="https://removed"
                behaviorConfiguration="ovrExClientBehavior"
                binding="basicHttpBinding"
                bindingConfiguration="WebServiceSOAP"
                contract="EWebService.EWebService"
                name="WebServiceSOAP" />
    </client>
    <extensions>
        <behaviorExtensions>
            <add name="exClientBehavior" type="ExMessageInspector.ExClientBehaviorExtensionElement, ExMessageInspector, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
        </behaviorExtensions>
    </extensions>
    <behaviors>
        <endpointBehaviors>
            <behavior name="ovrExClientBehavior">
                <exClientBehavior />
            </behavior>
        </endpointBehaviors>
    </behaviors>
</system.serviceModel>
<client>
   <endpoint address="https://removed" binding="basicHttpBinding" bindingConfiguration="WebServiceSOPA" contract="EWebService.EWebService" name="WebServiceSOAP">
    <headers>
     <wsse:Security s:mustUnderstand="0" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
      <wsse:UsernameToken wsu:Id="SecurityToken-3f7f983f-66ce-480d-bce6-170632d33f92" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
       <wsse:Username>User</wsse:Username>
       <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">Pwd123</wsse:Password>
      </wsse:UsernameToken>
     </wsse:Security>
    </headers>
   </endpoint>
  </client>