While working on an SOAP service I needed to create a number of clients for different languages. This would normally not be that big of a challenge except that the SOAP service had custom headers for doing authentication. Because of the complexity in setting up Axis to use WS-Security the choice was made to do authentication by adding a few out of band SOAP header values. The first few implementations went fine but then I came to C# and had a problem.
The problem was that using the auto-generated code from the WSDL didn’t provide any obvious way of adding the headers I needed to add. After a lot of digging I found an article on adding Support for Custom HTTP and SOAP Headers and that led me down the following path to a solution.
First off you need a custom header class that derives from SoapHeader. This class will contain the attributes that get sent in the SOAP header. Here is an example:
[code lang=”csharp”]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = “http://model.ioncannon.net”)]
[System.Xml.Serialization.XmlRootAttribute(“securitytoken”, Namespace = “http://model.ioncannon.net”, IsNullable = false)]
public class CustomHeader : SoapHeader
{
[System.Xml.Serialization.XmlTextAttribute()]
public string securitytoken;
}
[/code]
Next you will need an instance of the custom header in the generated service client. The variable name needs to match what gets stuck in something later so make it readable:
[code lang=”csharp”]
public CustomHeader creds;
[/code]
The final step is to a reference to the custom header before each call that requires the custom header. This is probably the least obvious part. The first line in the following code is the tie between the custom header instance created above and the generated “echo” service call:
[code lang=”csharp”]
[System.Web.Services.Protocols.SoapHeaderAttribute(“creds”, Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute(“urn:echo”, Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)]
[return: System.Xml.Serialization.XmlElementAttribute(“echoResponse”, Namespace=”http://model.ioncannon.net”)]
public echoResponse echo([System.Xml.Serialization.XmlElementAttribute(“echo”, Namespace=”http://model.ioncannon.net”)] echo echo1) {
object[] results = this.Invoke(“echo”, new object[] {echo1});
return ((echoResponse)(results[0]));
}
[/code]
Here is an example of calling the modified service:
[code lang=”csharp”]
CustomHeader mySoapHeader = new CustomHeader();
mySoapHeader.securitytoken = “testtoken”;
TestService client = new TestService();
client.creds = mySoapHeader;
echo request = new echo();
request.valueToEcho = “test”;
string echoValue = client.echo(request).@return;
Console.WriteLine(echoValue);
[/code]
The only downside to doing this is that regenerating the code from an updated WSDL will wipe out the changes.
Good morning, i’m from Italy and i have find the same problem with an axis webservice.
I pursued your same solution, giving a correct response from webservice;
but
“reference to the custom header before each call that requires the custom header”
and
“regenerating the code from an updated WSDL will wipe out the changes”
in the .Net 3.5 and VS2008 era…
Do you know if WSE or WCF could give any workaround ?
Thank you for attention.
Best regards.
You can use SoapExtension to insert header for each request. In this way, changes on generated proxy class is not required.
you can use message inspection it gives you great control on message
http://msdn.microsoft.com/en-us/library/aa717047.aspx