In the past I have needed to create custom SOAP headers in a C# project that was using an imported WSDL web reference. I found a way to do it but I was never happy with it and I have sense wondered if there was a better way. What I did was create a header that derives from SoapHeader:
在过去,我需要在使用导入的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;
}
I then had to modify the code that was generated from the WSDL and add a referen ce to an instance of the new header and the following before each web call that I wanted to contain the custom header:
然后,我必须修改从WSDL生成的代码,并在每个要包含自定义标头的Web调用之前向新标头的实例和以下内容添加引用:
[System.Web.Services.Protocols.SoapHeaderAttribute("instancename", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)]
Where "instancename" is the custom header's instance variable name in the generated class.
其中“instancename”是生成的类中的自定义标头的实例变量名称。
This works fine except that any change in the WSDL requires that it all be done over again since it regenerates the class. In other languages the headers can be added outside of the generated code so maybe I'm missing the way that is done in C#. Are there better ways of doing this?
这样可以正常工作,除了WSDL中的任何更改都要求重新完成它,因为它重新生成了类。在其他语言中,标题可以添加到生成的代码之外,所以可能我错过了在C#中完成的方式。有更好的方法吗?
4 个解决方案
#1
3
It seems that you are using .Net 2.0 and asmx webservices. Do you know that there is a framework called WCF (Windows Communication Framework) in .Net 3.0. I know that it is not easy to migrate to a new framework, but with WCF you get so much. Furthermore WCf can be used for so much more than WebServices (remoting, msmq and more). It is the framework that Microsoft is betting on for the future. Ie. manipulation a soap header is done using MessageContracts.
您似乎正在使用.Net 2.0和asmx webservices。您是否知道.Net 3.0中有一个名为WCF(Windows Communication Framework)的框架。我知道迁移到新框架并不容易,但是使用WCF你会得到很多。此外,WCf可以用于远远超过WebServices(远程处理,msmq等)。这是微软为未来投入的框架。 IE浏览器。使用MessageContracts操作soap标头。
So the answer is that in WCF you can do this with MessageContracts.
所以答案是在WCF中你可以用MessageContracts做到这一点。
#2
2
Beacuse of generated class is a partial class. You can define it on another file with same namespace and class name (again partial class). Then you can override its virtual methods and define it once.
生成的类的缺点是部分类。您可以在具有相同名称空间和类名称的另一个文件上定义它(再次是部分类)。然后,您可以覆盖其虚拟方法并定义一次。
This prevents further changes on regenerated class doesn't effect the one you wrote.
这可以防止对重新生成的类进行进一步更改不会影响您编写的类。
On new class file you can use "GetWriterForMessage" to override and add new SOAP headers to it.
在新的类文件上,您可以使用“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);
}
}
#3
0
There is a way to do it, sort of; it's not necessarily pretty, and on a very simple web service it may not be worth the effort, but it at least saves you from having to re-add the attributes in when you regenerate the code.
有一种方法可以做到这一点;它不一定很漂亮,而且在一个非常简单的Web服务上它可能不值得付出努力,但它至少可以让您不必在重新生成代码时重新添加属性。
Since the generator generates partial classes, you can:
由于生成器生成部分类,您可以:
-
Add a file to your project that extends the web service class (the one derived from SoapHttpClientProtocol) with another "partial" section (i.e., use the same namespace and name as the generated class, and mark it "partial").
向项目添加一个文件,该文件扩展了Web服务类(从SoapHttpClientProtocol派生的文件)和另一个“部分”部分(即,使用与生成的类相同的名称空间和名称,并将其标记为“部分”)。
-
Copy the methods you want to add the headers to (i.e., the same methods you've already been adding the attributes to) out of the generated code and paste them into your extension section.
从生成的代码中复制要添加标题的方法(即,您已添加属性的方法)并将其粘贴到扩展部分。
-
Rename the methods slightly so that they don't conflict with the ones in the generated code, and change the names that get passed to Invoke to match. (You may have to also tweak the other attributes on the methods to make sure they still map to the proper calls in the WSDL.)
稍微重命名方法,使它们不与生成的代码中的方法冲突,并更改传递给Invoke以匹配的名称。 (您可能还必须调整方法上的其他属性,以确保它们仍然映射到WSDL中的正确调用。)
-
Add the custom header attribute to the renamed methods, and the header instance field to your extension section as well.
将自定义标头属性添加到重命名的方法,并将标头实例字段添加到扩展部分。
-
Call the renamed versions from your code instead of the original versions.
从您的代码而不是原始版本调用重命名的版本。
As long as the method signatures don't change in the WSDL, you won't have to change anything in your code even if you regenerate. (Since you only copy the relatively short method implementations, any other structures from the WSDL will still come out of the generated code, so if they change you'll automatically get the updated versions when you regenerate. Granted, if the WSDL doesn't have any other structures in it, the utility of this is probably somewhat limited.)
只要方法签名在WSDL中没有变化,即使重新生成,也不必更改代码中的任何内容。 (由于您只复制相对较短的方法实现,因此WSDL中的任何其他结构仍将来自生成的代码,因此如果它们发生更改,您将在重新生成时自动获取更新的版本。但是,如果WSDL没有在其中有任何其他结构,其实用性可能有些限制。)
It's still not ideal, but short of trying to intercept the raw XML message and put the header in directly (which you could probably do, but it would be nasty), there aren't really any other options that I know of (without moving over to WCF anyway).
它仍然不理想,但没有尝试拦截原始XML消息并直接放入标题(你可能会这样做,但它会很糟糕),我知道没有其他任何选项(没有移动)无论如何,转到WCF)。
#4
0
I ran into this problem today. I ended creating a class that derives from the autogenerated class and overriding the GetWriterForMessage method to ensure my header was always present. I would update the header value on every call to the method.
我今天遇到了这个问题。我结束了创建一个派生自自动生成的类并重写GetWriterForMessage方法的类,以确保我的标题始终存在。我会在每次调用方法时更新标头值。
#1
3
It seems that you are using .Net 2.0 and asmx webservices. Do you know that there is a framework called WCF (Windows Communication Framework) in .Net 3.0. I know that it is not easy to migrate to a new framework, but with WCF you get so much. Furthermore WCf can be used for so much more than WebServices (remoting, msmq and more). It is the framework that Microsoft is betting on for the future. Ie. manipulation a soap header is done using MessageContracts.
您似乎正在使用.Net 2.0和asmx webservices。您是否知道.Net 3.0中有一个名为WCF(Windows Communication Framework)的框架。我知道迁移到新框架并不容易,但是使用WCF你会得到很多。此外,WCf可以用于远远超过WebServices(远程处理,msmq等)。这是微软为未来投入的框架。 IE浏览器。使用MessageContracts操作soap标头。
So the answer is that in WCF you can do this with MessageContracts.
所以答案是在WCF中你可以用MessageContracts做到这一点。
#2
2
Beacuse of generated class is a partial class. You can define it on another file with same namespace and class name (again partial class). Then you can override its virtual methods and define it once.
生成的类的缺点是部分类。您可以在具有相同名称空间和类名称的另一个文件上定义它(再次是部分类)。然后,您可以覆盖其虚拟方法并定义一次。
This prevents further changes on regenerated class doesn't effect the one you wrote.
这可以防止对重新生成的类进行进一步更改不会影响您编写的类。
On new class file you can use "GetWriterForMessage" to override and add new SOAP headers to it.
在新的类文件上,您可以使用“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);
}
}
#3
0
There is a way to do it, sort of; it's not necessarily pretty, and on a very simple web service it may not be worth the effort, but it at least saves you from having to re-add the attributes in when you regenerate the code.
有一种方法可以做到这一点;它不一定很漂亮,而且在一个非常简单的Web服务上它可能不值得付出努力,但它至少可以让您不必在重新生成代码时重新添加属性。
Since the generator generates partial classes, you can:
由于生成器生成部分类,您可以:
-
Add a file to your project that extends the web service class (the one derived from SoapHttpClientProtocol) with another "partial" section (i.e., use the same namespace and name as the generated class, and mark it "partial").
向项目添加一个文件,该文件扩展了Web服务类(从SoapHttpClientProtocol派生的文件)和另一个“部分”部分(即,使用与生成的类相同的名称空间和名称,并将其标记为“部分”)。
-
Copy the methods you want to add the headers to (i.e., the same methods you've already been adding the attributes to) out of the generated code and paste them into your extension section.
从生成的代码中复制要添加标题的方法(即,您已添加属性的方法)并将其粘贴到扩展部分。
-
Rename the methods slightly so that they don't conflict with the ones in the generated code, and change the names that get passed to Invoke to match. (You may have to also tweak the other attributes on the methods to make sure they still map to the proper calls in the WSDL.)
稍微重命名方法,使它们不与生成的代码中的方法冲突,并更改传递给Invoke以匹配的名称。 (您可能还必须调整方法上的其他属性,以确保它们仍然映射到WSDL中的正确调用。)
-
Add the custom header attribute to the renamed methods, and the header instance field to your extension section as well.
将自定义标头属性添加到重命名的方法,并将标头实例字段添加到扩展部分。
-
Call the renamed versions from your code instead of the original versions.
从您的代码而不是原始版本调用重命名的版本。
As long as the method signatures don't change in the WSDL, you won't have to change anything in your code even if you regenerate. (Since you only copy the relatively short method implementations, any other structures from the WSDL will still come out of the generated code, so if they change you'll automatically get the updated versions when you regenerate. Granted, if the WSDL doesn't have any other structures in it, the utility of this is probably somewhat limited.)
只要方法签名在WSDL中没有变化,即使重新生成,也不必更改代码中的任何内容。 (由于您只复制相对较短的方法实现,因此WSDL中的任何其他结构仍将来自生成的代码,因此如果它们发生更改,您将在重新生成时自动获取更新的版本。但是,如果WSDL没有在其中有任何其他结构,其实用性可能有些限制。)
It's still not ideal, but short of trying to intercept the raw XML message and put the header in directly (which you could probably do, but it would be nasty), there aren't really any other options that I know of (without moving over to WCF anyway).
它仍然不理想,但没有尝试拦截原始XML消息并直接放入标题(你可能会这样做,但它会很糟糕),我知道没有其他任何选项(没有移动)无论如何,转到WCF)。
#4
0
I ran into this problem today. I ended creating a class that derives from the autogenerated class and overriding the GetWriterForMessage method to ensure my header was always present. I would update the header value on every call to the method.
我今天遇到了这个问题。我结束了创建一个派生自自动生成的类并重写GetWriterForMessage方法的类,以确保我的标题始终存在。我会在每次调用方法时更新标头值。