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

在过去,我需要在使用导入的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#中完成的方式。 有更好的方法吗?

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

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

生成的类的缺点是部分类。 您可以在具有相同名称空间和类名称的另一个文件上定义它(再次是部分类)。 然后,您可以覆盖其虚拟方法并定义一次。

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

在新的类文件上,您可以使用“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); } } 

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

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

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

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

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

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

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

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

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

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