1

过去,我需要在使用导入的 WSDL Web 引用的 C# 项目中创建自定义 SOAP 标头。我找到了一种方法来做到这一点,但我对此并不满意,我想知道是否有更好的方法。我所做的是创建一个从 SoapHeader 派生的标头:

[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://model.test.net")]
[System.Xml.Serialization.XmlRootAttribute("securitytoken", Namespace = "http://model.test.net", IsNullable = false)]
public class SpecialHeader : SoapHeader
{ 
  [System.Xml.Serialization.XmlTextAttribute()]
  public string aheadervalue;
}

然后,我必须修改从 WSDL 生成的代码,并在我想要包含自定义标头的每个 Web 调用之前添加对新标头实例和以下内容的引用:

[System.Web.Services.Protocols.SoapHeaderAttribute("instancename", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)]

其中“instancename”是生成的类中自定义标头的实例变量名称。

这工作得很好,除了 WSDL 中的任何更改都需要重新完成,因为它会重新生成类。在其他语言中,可以在生成的代码之外添加标头,所以也许我错过了在 C# 中完成的方式。有没有更好的方法来做到这一点?

4

4 回答 4

3

看来您正在使用 .Net 2.0 和 asmx webservices。你知道.Net 3.0中有一个叫WCF(Windows Communication Framework)的框架吗?我知道迁移到一个新的框架并不容易,但是有了 WCF,你会得到很多。此外,WCf 的用途远不止 WebServices(远程处理、msmq 等)。这是微软为未来押注的框架。IE。使用 MessageContracts 操作肥皂头。

所以答案是在 WCF 中你可以使用 MessageContracts 来做到这一点。

于 2008-12-17T15:27:47.270 回答
2

因为生成的类是部分类。您可以在另一个具有相同命名空间和类名的文件上定义它(同样是部分类)。然后你可以覆盖它的虚拟方法并定义一次。

这可以防止对重新生成的类的进一步更改不会影响您编写的类。

在新的类文件上,您可以使用“GetWriterForMessage”来覆盖并向其添加新的 SOAP 标头。

public partial class SampleService
{
    public string MessageID { get; set; }

    protected override System.Xml.XmlWriter GetWriterForMessage(System.Web.Services.Protocols.SoapClientMessage message, int bufferSize)
    {
        message.Headers.Add(new UsernameSoapHeader("Username"));
        message.Headers.Add(new PasswordSoapHeader("Password"));
        message.Headers.Add(new MessageIDSoapHeader(MessageID));
        return base.GetWriterForMessage(message, bufferSize);
    }
}
于 2011-06-30T07:54:05.070 回答
1

有一种方法可以做到这一点;它不一定很漂亮,在一个非常简单的 Web 服务上,它可能不值得付出努力,但它至少可以让您在重新生成代码时不必重新添加属性。

由于生成器生成部分类,您可以:

  1. 将一个文件添加到您的项目中,该文件使用另一个“部分”部分(即,使用与生成的类相同的名称空间和名称,并将其标记为“部分”)扩展 Web 服务类(从 SoapHttpClientProtocol 派生的)。

  2. 从生成的代码中复制您想要添加标题的方法(即,您已经添加属性的相同方法)并将它们粘贴到您的扩展部分。

  3. 稍微重命名这些方法,以便它们不会与生成的代码中的方法冲突,并更改传递给 Invoke 的名称以匹配。(您可能还必须调整方法上的其他属性,以确保它们仍然映射到 WSDL 中的正确调用。)

  4. 将自定义标头属性添加到重命名的方法中,并将标头实例字段添加到您的扩展部分。

  5. 从您的代码中调用重命名的版本而不是原始版本。

只要方法签名在 WSDL 中没有更改,即使重新生成,您也不必更改代码中的任何内容。(由于您只复制相对较短的方法实现,WSDL 中的任何其他结构仍然会从生成的代码中出来,因此如果它们发生更改,您将在重新生成时自动获得更新的版本。当然,如果 WSDL 没有有任何其他结构,它的效用可能有些有限。)

它仍然不理想,但没有尝试拦截原始 XML 消息并将标头直接放入(您可能会这样做,但它会很讨厌),实际上没有任何其他我知道的选项(无需移动无论如何都要转到WCF)。

于 2008-12-02T04:44:44.940 回答
0

我今天遇到了这个问题。我结束了创建从自动生成的类派生的类并覆盖GetWriterForMessage方法以确保我的标头始终存在。我会在每次调用该方法时更新标头值。

于 2010-04-13T16:40:25.323 回答