如何在WCF中添加自定义SOAP标头?

32

在basicHttpBinding中,我是否可以像在ASMX Web服务中添加自定义身份验证标头一样,在WCF传入/传出消息中添加自定义SOAP标头?这些自定义SOAP标头应该可通过.NET 2.0 / 1.1 Web服务客户端访问(可通过WSDL.EXE工具访问)。


我更新了我的答案,并添加了有关消息检查器的信息。 - marc_s
我再次更新了我的答案,并提供了关于ASMX/WCF与SOAP头部互操作性的信息。 - marc_s
2个回答

29

请查看WCF Extras在Codeplex上的链接 - 它是一个简单的WCF扩展库,其中包含自定义SOAP头等内容。

另一个选项是在您的WCF服务中使用WCF消息契约 - 这也可以轻松地让您定义和设置WCF SOAP头。

[MessageContract]
public class BankingTransaction
{
  [MessageHeader]
  public Operation operation;
  [MessageHeader] 
  public DateTime transactionDate;

  [MessageBodyMember] 
  private Account sourceAccount;
  [MessageBodyMember] 
  private Account targetAccount;
  [MessageBodyMember] 
  public int amount;
}

在这里,“operation”和“transactionDate”被定义为SOAP标头。

如果上述方法都无法帮助您,那么您应该了解WCF消息检查器的概念,您可以将其编写为扩展。它们允许您在客户端的每个传出调用中注入某些标头,并从消息中检索这些标头以供您使用。

请参阅此博客文章通过WCF行为处理自定义SOAP标头作为编写消息检查器的起点,以及如何将其包含在项目设置中。

客户端侧的IClientMessageInspector定义了两个方法BeforeSendRequestAfterReceiveReply,而服务器侧的IDispatchMessageInspector具有相反的方法,即AfterReceiveRequestBeforeSendReply

有了这个,您可以向通过网络传输的每个消息添加标头(或仅选择性地添加到其中一些消息)。

下面是我们使用的IClientMessageInspector实现者的片段,用于自动传输区域设置信息(语言和文化信息)从客户端到服务器,这应该能给您一个开始的想法:

public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
    International intlHeader = new International();
    intlHeader.Locale = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;

    MessageHeader header = MessageHeader.CreateHeader(WSI18N.ElementNames.International, WSI18N.NamespaceURI, intlHeader);
    request.Headers.Add(header);

    return null;
}
在服务器端,您将检查这些标题是否存在,如果存在,则从SOAP信封中提取它们并使用它们。更新:好的消息是,您的客户端正在使用.NET 2.0而且没有使用WCF。此时仍然可以正常工作,请参阅此博客文章“自定义SOAP标头:WCF和ASMX”以获取详细信息。在服务器端仍然可以使用消息检查器来嗅探和提取由.NET 2.0客户端发送的自定义标头。

感谢marc_s,我尝试使用WCF Extras,我向服务契约添加了“XmlSerializerFormat”属性,但在访问服务时,WCF Extras会引发错误。 是否有其他可用的解决方案,例如WCF Extras? 我是否可以将MessageContract添加为每个方法的属性,就像我在ASMX服务中添加SoapHeader一样? 我的要求是,我需要在对WCF服务进行每次调用时发送一些数据(例如用户名和密码)。 有没有办法实现这个需求? - nRk
嗨,Marc_s,看起来很不错。但是在文章中提到客户端应该使用 .net 3.0 或更高版本。但在我的情况下,客户端使用的是 .net 2.0 和 1.1。是否仍然可以实现这个呢? - nRk

3

我认为这个解决方案更为简单:

            var client = "Your Service Client"; 
            using (var scope = new OperationContextScope(client.InnerChannel))
            {
                System.Xml.XmlDocument document = new XmlDocument();
                XmlElement element = document.CreateElement("wsse", "UsernameToken", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");

                XmlElement newChild = null;
                newChild = document.CreateElement("wsse", "Username", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
                newChild.InnerText = "finance";
                element.AppendChild(newChild);

                newChild = document.CreateElement("wsse", "CorporationCode", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
                newChild.InnerText = "387";
                element.AppendChild(newChild);

                MessageHeader messageHeader = MessageHeader.CreateHeader("UsernameToken", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", element, false);

                OperationContext.Current.OutgoingMessageHeaders.Add(messageHeader);

                var result = client.GetCorporations(new CorporationType { pageNo = 1 });
            }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接