473,387 Members | 1,721 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

Inserting a SOAP Header in a client request

I have a C#/.Net 1.1 client talking to a Java based web service. I need to
insert a soap header on the client side which is expected on the server side.
Currently, the Java ws provider, Axis, does not support automatic wsdl
generation of custom headers so the wsdl has no information regarding the
required header.

I've read through a lot of material and managed to get a workable solution
but it is far from ideal.

I created a new AuthHeader:SoapHeader class and updated the client ws proxy
to make use of the new header. This worked but I want to avoid having to
modify tool generated code. I don't want to touch the .Net wsdl.exe
generated ws proxy.

One other solution may be to modify the stream via my own SoapExtension
class. Problem is that requires working at a low level on the stream. Why
should I have to do that when .Net provides a rich SOAP API?

I would think I should be able to simply insert my own SoapHeader into the
SoapMessage via SoapExtension.ProcessMessage(). I have tried this approach
without success. I get a System.InvalidOperationException upon attempted
serialization of the SoapMessage. The error is, "The type
SimpleWSClient.AuthHeader was not expected. Use the XmlInclude or SoapInclude
attribute to specify types that are not known statically." It seems like
this approach should work. I assumed that a SoapHeader object would already
know how to serialize itself if it contains only basic types.

My SoapHeader and SoapExtension classes below:

using System;
using System.Xml.Serialization;
using System.Web.Services.Protocols;

namespace SimpleWSClient
{
public class AuthHeader : SoapHeader
{
private string userName;
private string password;

public AuthHeader()
{
}

public AuthHeader(string user, string pwd)
{
UserName = user;
Password = pwd;
}

public string UserName
{
get { return userName; }
set { userName = value; }
}

public string Password
{
get { return password; }
set { password = value; }
}
}

}

using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml;
using System.Xml.Serialization;

namespace SimpleWSClient
{
/// <summary>
/// SOAP Extension that checks the SOAP Header for a username and password
/// and does the necessary authentication and authorization.
/// </summary>
public class UsernamePasswordSoapExtension : SoapExtension
{

public override object GetInitializer( Type serviceType )
{
return null;
}

public override object GetInitializer( LogicalMethodInfo methodInfo,
SoapExtensionAttribute attribute )
{
return null;
}

public override void Initialize( object initializer )
{
}

public override void ProcessMessage( SoapMessage message )
{
if (message.Stage == SoapMessageStage.BeforeSerialize)
{
SecurityContext context = SecurityContext.getInstance();
AuthHeader soapHeader = new AuthHeader(context.UserName,
context.Password);
SoapClientMessage scm = (SoapClientMessage)message;
SoapHeaderCollection headers = scm.Headers;
headers.Add(soapHeader);
}
}

}
}
This last approach is what I am after. It would allow me to insert a custom
SoapHeader using a high-level Soap API without having to inject custom code
into a tool generated ws proxy.

Is it possible to make this last approach work or am I forced to work with
the first two options?

Thanks.
Nov 23 '05 #1
6 20200
Hello john,
I dont see the difference in what you call the second option and the
third option. What you seem to be missing is overriding the chain stream
and writing to the stream (which I gather you dont wish to do). The problem
with your code is .. yes you're using the soap object model to add the header
but you've failed to modify the stream by writing that information back into
the stream. Also have you considered using WSE? and also are you sure the
java service is not using WS-Security? If it is, you would need to send standard
username tokens as opposed to a custom auth header

HTH
Regards,
Dilip Krishnan
MCAD, MCSD.net
dkrishnan at geniant dot com
http://www.geniant.com
I have a C#/.Net 1.1 client talking to a Java based web service. I
need to
insert a soap header on the client side which is expected on the
server side.
Currently, the Java ws provider, Axis, does not support automatic
wsdl
generation of custom headers so the wsdl has no information regarding
the
required header.

I've read through a lot of material and managed to get a workable
solution but it is far from ideal.

I created a new AuthHeader:SoapHeader class and updated the client ws
proxy to make use of the new header. This worked but I want to avoid
having to modify tool generated code. I don't want to touch the .Net
wsdl.exe generated ws proxy.

One other solution may be to modify the stream via my own
SoapExtension class. Problem is that requires working at a low level
on the stream. Why should I have to do that when .Net provides a rich
SOAP API?

I would think I should be able to simply insert my own SoapHeader into
the SoapMessage via SoapExtension.ProcessMessage(). I have tried this
approach without success. I get a System.InvalidOperationException
upon attempted serialization of the SoapMessage. The error is, "The
type SimpleWSClient.AuthHeader was not expected. Use the XmlInclude or
SoapInclude attribute to specify types that are not known statically."
It seems like this approach should work. I assumed that a SoapHeader
object would already know how to serialize itself if it contains only
basic types.

My SoapHeader and SoapExtension classes below:

using System;
using System.Xml.Serialization;
using System.Web.Services.Protocols;
namespace SimpleWSClient
{
public class AuthHeader : SoapHeader
{
private string userName;
private string password;
public AuthHeader()
{
}
public AuthHeader(string user, string pwd)
{
UserName = user;
Password = pwd;
}
public string UserName
{
get { return userName; }
set { userName = value; }
}
public string Password
{
get { return password; }
set { password = value; }
}
}
}

using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml;
using System.Xml.Serialization;
namespace SimpleWSClient
{
/// <summary>
/// SOAP Extension that checks the SOAP Header for a username and
password
/// and does the necessary authentication and authorization.
/// </summary>
public class UsernamePasswordSoapExtension : SoapExtension
{
public override object GetInitializer( Type serviceType )
{
return null;
}
public override object GetInitializer( LogicalMethodInfo methodInfo,
SoapExtensionAttribute attribute )
{
return null;
}
public override void Initialize( object initializer )
{
}
public override void ProcessMessage( SoapMessage message )
{
if (message.Stage == SoapMessageStage.BeforeSerialize)
{
SecurityContext context = SecurityContext.getInstance();
AuthHeader soapHeader = new AuthHeader(context.UserName,
context.Password);
SoapClientMessage scm = (SoapClientMessage)message;
SoapHeaderCollection headers = scm.Headers;
headers.Add(soapHeader);
}
}
}
}
This last approach is what I am after. It would allow me to insert a
custom SoapHeader using a high-level Soap API without having to inject
custom code into a tool generated ws proxy.

Is it possible to make this last approach work or am I forced to work
with the first two options?

Thanks.

Nov 23 '05 #2
Sorry if my original post was not clear. Let me clarify the options I was
exploring:

Option 1: custom SoapHeader and modify the ws client proxy by hand to
reference the new SoapHeader..

Option 2: custom SoapExtension and modify the stream by hand via
ChainStream().

Option 3: custom Soap Extension and SoapHeader and modify the SoapMessage
via ProcessMessage().

So, it sounds like option 3 is not really an option. Option 2 means working
with a byte stream instead of a Soap API. ChainStream() is the only place we
can modify the message before serialization? I guess I'm still not quite
clear on the distinction between ChainStream() and ProcessMessage().

Given that this is all in the context of a web service request, I shouldn't
have to work at the byte level to add a soap header to a soap message. I
imagine the Stream could somehow be converted to a SoapMessage before adding
the soap header but that would be inefficient given that it will be converted
into a SoapMessage later in the call chain.

WSE is something I will explore but for the time being this is what I am
working with. I need to research Axis 1.1 support of WS-Security and compare
it to .Net.
The server side of this solution already exists and works for a different
client implementation.

Clean insertion of a custom soap header on the client side should be
relatively painless. This is how it's done in Axis (Java):

// setup authorization header
SOAPHeaderElement authHeader = new SOAPHeaderElement( "",
"AuthHeader" );
MessageElement usernameElement = ( MessageElement )
authHeader.addChildElement( "UserName" );
MessageElement passwordElement = ( MessageElement )
authHeader.addChildElement( "Password" );
usernameElement.setObjectValue("jdoe");
passwordElement.setObjectValue("password");
call.addHeader( authHeader );

John

"Dilip Krishnan" wrote:
Hello john,
I dont see the difference in what you call the second option and the
third option. What you seem to be missing is overriding the chain stream
and writing to the stream (which I gather you dont wish to do). The problem
with your code is .. yes you're using the soap object model to add the header
but you've failed to modify the stream by writing that information back into
the stream. Also have you considered using WSE? and also are you sure the
java service is not using WS-Security? If it is, you would need to send standard
username tokens as opposed to a custom auth header

HTH
Regards,
Dilip Krishnan
MCAD, MCSD.net
dkrishnan at geniant dot com
http://www.geniant.com


Nov 23 '05 #3
I reviewed the article, "Altering the SOAP Message Using SOAP Extensions". I
see that update of the soap message requires overrides in both ChainStream()
and ProcessMessage().

What I don't understand is why I'm not able to update the soap message via
the SoapMessage API. ProcessMessage() is passed a SoapMessage object but it
can't be directly updated, I am forced to update a byte stream instead.
SoapExtension inherits from System.Object so I'm puzzled why updates are only
allowed via a byte stream.

Are there any other options?
Nov 23 '05 #4
Hello john,
You really dont have to play around with bits and bytes. Every Soap based
Object has a LoadXml and GetXml that you can use in conjunction with a XmlTextReader/Writer.
So all you need to do is write to the chained stream using an xml writer.
But u do have to chain the stream to be able to alter the stream
HTH
Regards,
Dilip Krishnan
MCAD, MCSD.net
dkrishnan at geniant dot com
http://www.geniant.com
Sorry if my original post was not clear. Let me clarify the options I
was exploring:

Option 1: custom SoapHeader and modify the ws client proxy by hand to
reference the new SoapHeader..

Option 2: custom SoapExtension and modify the stream by hand via
ChainStream().

Option 3: custom Soap Extension and SoapHeader and modify the
SoapMessage via ProcessMessage().

So, it sounds like option 3 is not really an option. Option 2 means
working with a byte stream instead of a Soap API. ChainStream() is
the only place we can modify the message before serialization? I
guess I'm still not quite clear on the distinction between
ChainStream() and ProcessMessage().

Given that this is all in the context of a web service request, I
shouldn't have to work at the byte level to add a soap header to a
soap message. I imagine the Stream could somehow be converted to a
SoapMessage before adding the soap header but that would be
inefficient given that it will be converted into a SoapMessage later
in the call chain.

WSE is something I will explore but for the time being this is what I
am
working with. I need to research Axis 1.1 support of WS-Security and
compare
it to .Net.
The server side of this solution already exists and works for a
different
client implementation.
Clean insertion of a custom soap header on the client side should be
relatively painless. This is how it's done in Axis (Java):

// setup authorization header
SOAPHeaderElement authHeader = new SOAPHeaderElement( "",
"AuthHeader" );
MessageElement usernameElement = ( MessageElement )
authHeader.addChildElement( "UserName" );
MessageElement passwordElement = ( MessageElement )
authHeader.addChildElement( "Password" );
usernameElement.setObjectValue("jdoe");
passwordElement.setObjectValue("password");
call.addHeader( authHeader );
John

"Dilip Krishnan" wrote:
Hello john,
I dont see the difference in what you call the second option and the
third option. What you seem to be missing is overriding the chain
stream
and writing to the stream (which I gather you dont wish to do). The
problem
with your code is .. yes you're using the soap object model to add
the header
but you've failed to modify the stream by writing that information
back into
the stream. Also have you considered using WSE? and also are you sure
the
java service is not using WS-Security? If it is, you would need to
send standard
username tokens as opposed to a custom auth header
HTH
Regards,
Dilip Krishnan
MCAD, MCSD.net
dkrishnan at geniant dot com
http://www.geniant.com

Nov 23 '05 #5
So, my SoapHeader object has a GetXml() implementation that is not public?

Can you point to some examples that demonstrate this?

How do I write the header to the stream in the correct place? I understand
that the SoapExtension has a priority and group associated it and that the
priority is relative. But relative to what? I am using an App.config file
to declare the soap extension. Assuming my SoapHeader already knows how to
write the correct XML for itself how do I ensure that my SoapHeader is
written inside the Envelope but before the Body?

"Dilip Krishnan" wrote:
Hello john,
You really dont have to play around with bits and bytes. Every Soap based
Object has a LoadXml and GetXml that you can use in conjunction with a XmlTextReader/Writer.
So all you need to do is write to the chained stream using an xml writer.
But u do have to chain the stream to be able to alter the stream
HTH
Regards,
Dilip Krishnan
MCAD, MCSD.net
dkrishnan at geniant dot com
http://www.geniant.com


Nov 23 '05 #6
Hello john,
Something like this...

private void AddViaElementToHeader(SoapMessage message ) //message that
comes in the process message
{
ISoapFormatter formatter = WebServicesConfiguration.MessagingConfiguration.As mxPlainFormatter;
SoapEnvelope env = null;
if(message is SoapServerMessage)
{
try
{
if (!message.ContentType.StartsWith(WebServicesConfig uration.MessagingConfiguration.AsmxPlainFormatter. ContentType))
//This is a hack
{
formatter = WebServicesConfiguration.MessagingConfiguration.As mxAttachmentFormatter;
}

env = formatter.Deserialize(_originalStream); //message from stream
}
catch(Exception)
{
HttpContext.Current.Response.StatusCode = 400;
HttpContext.Current.Response.Buffer = false;
HttpContext.Current.Response.OutputStream.Flush();
HttpContext.Current.ApplicationInstance.CompleteRe quest();
return;
}
XmlElement header = null;
header = env.CreateElement("yrHeader", YourNamespaceURI);
header .InnerText = this.ServiceUrl;
env.Header.AppendChild(header);
}
env.Save(_replacedStream); //Stream that you chained
if (this._replacedStream.CanSeek)
{
this._replacedStream.Position = 0;
}

}
HTH
Regards,
Dilip Krishnan
MCAD, MCSD.net
dkrishnan at geniant dot com
http://www.geniant.com
So, my SoapHeader object has a GetXml() implementation that is not
public?

Can you point to some examples that demonstrate this?

How do I write the header to the stream in the correct place? I
understand that the SoapExtension has a priority and group associated
it and that the priority is relative. But relative to what? I am
using an App.config file to declare the soap extension. Assuming my
SoapHeader already knows how to write the correct XML for itself how
do I ensure that my SoapHeader is written inside the Envelope but
before the Body?

"Dilip Krishnan" wrote:
Hello john,
You really dont have to play around with bits and bytes. Every Soap
based
Object has a LoadXml and GetXml that you can use in conjunction with
a XmlTextReader/Writer.
So all you need to do is write to the chained stream using an xml
writer.
But u do have to chain the stream to be able to alter the stream
HTH
Regards,
Dilip Krishnan
MCAD, MCSD.net
dkrishnan at geniant dot com
http://www.geniant.com

Nov 23 '05 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: ramas | last post by:
Hi, I am new to PHP scripting and i am trying to connect to a soap server (as mentioned below) using the SOAP extension comesup with PHP. Now my requirement is to add my HTTP header fields along...
5
by: jb | last post by:
*Please* help --- I'm tearing my hair out. I want to use sessionstate in a webservice, accessed from a client, written in script (JScript, InfoPath). I have written my webservice (C# .NET). I...
3
by: Sydney | last post by:
Hi, I am trying to construct a WSE 2.0 security SOAP request in VBScript on an HTML page to send off to a webservice. I think I've almost got it but I'm having an issue generating the nonce...
5
by: vthakur | last post by:
Hello: I have a Axis Web Service that sets the sessionid in the SOAP header for persisting the session. The client is a .Net client that processes the header as an Unknown Header. It sets the...
0
by: Grzegorz Smith | last post by:
Hi All. I 'm learning ZSI to use SOAP and I desperately need help. I'm working on example from tutorial -(examples/server/send_response/ simple/wsdl/). Here are my wsdl files...
4
by: Joseph Geretz | last post by:
We use a Soap Header to pass a token class (m_Token) back and forth with authenticated session information. Given the following implementation for our Logout method, I vastly prefer to simply code...
6
by: John | last post by:
I'm trying to call a Webservice (Non-.NET) That requires the insertion of security credentials into the SOAP header. Up until know I've been creating Dynamic proxy classes to call web services and...
7
by: beachdog | last post by:
I'm using Visual Studio 2005/C# to build a web client. The web server is something I've written in a different framework, which does not support generating wsdl, so I have hand-built a wsdl file,...
0
by: vigneshrao | last post by:
Hi, I have been working on a script that loops through multiple records and sends data (one record per call) to a WS. I am supposed to make a new call for each record before sending the data....
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.