过去,我需要在使用导入的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#中完成的方式。有更好的方法吗?
答案 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服务上,它可能不值得付出努力,但它至少可以让您不必在重新生成代码时重新添加属性。
由于生成器生成了部分类,您可以:
向项目添加一个文件,该文件扩展了Web服务类(从SoapHttpClientProtocol派生的文件)和另一个“部分”部分(即,使用与生成的类相同的名称空间和名称,并将其标记为“partial” “)。
从生成的代码中复制要添加标题的方法(即,您已添加属性的方法)并将其粘贴到扩展部分。
< / LI>稍微重命名方法,使它们不与生成的代码中的方法冲突,并更改传递给Invoke以匹配的名称。 (您可能还必须调整方法上的其他属性,以确保它们仍然映射到WSDL中的正确调用。)
将自定义标题属性添加到重命名的方法,并将标题实例字段添加到您的扩展部分。
从您的代码而不是原始版本调用重命名的版本。
只要方法签名在WSDL中没有变化,即使重新生成,也不必更改代码中的任何内容。 (由于您只复制相对较短的方法实现,因此WSDL中的任何其他结构仍将来自生成的代码,因此如果它们发生更改,您将在重新生成时自动获取更新的版本。当然,如果WSDL没有在其中有任何其他结构,其实用性可能有些限制。)
它仍然不理想,但是没有尝试拦截原始XML消息并将标题直接放入(你可能会这样做,但它会很糟糕),我所知道的其他选项并不存在(无论如何都没有转移到WCF)。
答案 3 :(得分:0)
我今天遇到了这个问题。我结束了创建一个派生自自动生成的类并覆盖GetWriterForMessage方法的类,以确保我的标题始终存在。我会在每次调用方法时更新标头值。