有没有更好的方法在C#中自定义SOAP头?

时间:2008-12-01 16:01:31

标签: c# .net web-services soap asmx

过去,我需要在使用导入的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调用之前,ce到新标题的实例和以下内容 我想要包含自定义标题:

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

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

这很好用,除了WSDL中的任何更改都需要重新完成它,因为它重新生成了类。在其他语言中,标题可以在生成的代码之外添加,所以可能我错过了在C#中完成的方式。有更好的方法吗?

4 个答案:

答案 0 :(得分:3)

您似乎正在使用.Net 2.0和asmx webservices。 您是否知道.Net 3.0中有一个名为WCF(Windows Communication Framework)的框架。 我知道迁移到新框架并不容易,但是使用WCF你会得到很多。 此外,WCf可以用于远远超过WebServices(远程处理,msmq等)。这是微软为未来投注的框架。 IE浏览器。使用MessageContracts来处理soap标头。

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

答案 1 :(得分: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);
    }
}

答案 2 :(得分:0)

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

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

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

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

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

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

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

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

    它仍然不理想,但是没有尝试拦截原始XML消息并将标题直接放入(你可能会这样做,但它会很糟糕),我所知道的其他选项并不存在(无论如何都没有转移到WCF)。

答案 3 :(得分:0)

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