After searching, I found out that WS-Security is a standard.
Then, I try to find out where I can insert the header to the requested XML. Below it's a one of the solutions that I found out on ASP.NET forum.
WSHeader .cs
public class WSHeader : SoapExtension
{
public bool outgoing = true;
public bool incoming = false;
private Stream outputStream;
public Stream oldStream;
public Stream newStream;
// The ChainStream, GetInitializers, Initialize, and ProcessMessage are required
// for a Soap override. ChainStream and ProcessMessage are what we need.
/// <summary>
/// Override. Save old stream, create new one.
/// </summary>
/// <param name="stream"></param>
/// <returns></returns>
public override Stream ChainStream(Stream stream)
{
// save a copy of the stream, create a new one for manipulating.
this.outputStream = stream;
oldStream = stream;
newStream = new MemoryStream();
return newStream;
}
#region "overrides of no interest"
public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
{
throw new Exception("The method or operation is not implemented.");
}
public override object GetInitializer(Type serviceType)
{
return null;
}
public override void Initialize(object initializer)
{
return;
}
#endregion
/// <summary>
/// Return a string version of the XML
/// </summary>
/// <returns></returns>
public string getXMLFromCache()
{
newStream.Position = 0; // start at the beginning!
string strSOAPresponse = ExtractFromStream(newStream);
return strSOAPresponse;
}
/// <summary>
/// Transfer the text from the target stream from the
/// current position.
/// </summary>
/// <param name="target"></param>
/// <returns></returns>
private String ExtractFromStream(Stream target)
{
if (target != null)
return (new StreamReader(target)).ReadToEnd();
return "";
}
/// <summary>
/// Override. Process .AfterSerialize and .BeforeDeserialize
/// to insert a non-standard SOAP header with username and
/// password (currently hard-coded).
/// </summary>
/// <param name="message"></param>
public override void ProcessMessage(SoapMessage message)
{
StreamReader readStr;
StreamWriter writeStr;
string soapMsg1;
XmlDocument xDoc = new XmlDocument();
// a SOAP message has 4 stages. We're interested in .AfterSerialize
switch (message.Stage)
{
case SoapMessageStage.BeforeSerialize:
break;
case SoapMessageStage.AfterSerialize:
{
// Get the SOAP body as a string, so we can manipulate...
String soapBodyString = getXMLFromCache();
// Strip off the old header stuff before the message body
// I'm not completely sure, but the soap:encodingStyle might be
// unique to the WebSphere environment. Dunno.
String BodString = "<soap:Body>";
int pos1 = soapBodyString.IndexOf(BodString) + BodString.Length;
int pos2 = soapBodyString.Length - pos1;
soapBodyString = soapBodyString.Substring(pos1, pos2);
soapBodyString = "<soap:Body>" + soapBodyString;
// Create the SOAP Message
// It's comprised of a <soap:Element> that's enclosed in <soap:Body>.
// Pack the XML document inside the <soap:Body> element
//String xmlVersionString = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
String soapEnvelopeBeginString = "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:tns=\"http://tempuri.org/\" xmlns:types=\"http://tempuri.org/encodedTypes\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">";
String soapEnvHeaderString = "<soap:Header><Security><UsernameToken><Username>";
String soapEnvHeaderString2 = "</Username><Password>";
String soapEnvHeaderString3 = "</Password></UsernameToken></Security></soap:Header>";
Stream appOutputStream = new MemoryStream();
StreamWriter soapMessageWriter = new StreamWriter(appOutputStream);
//soapMessageWriter.Write(xmlVersionString);
soapMessageWriter.Write(soapEnvelopeBeginString);
//// The heavy-handed part - forcing the right headers AND the uname/pw :)
soapMessageWriter.Write(soapEnvHeaderString);
soapMessageWriter.Write(ConfigurationManager.AppSettings["WSUserName"]);
soapMessageWriter.Write(soapEnvHeaderString2);
soapMessageWriter.Write(ConfigurationManager.AppSettings["WSPassword"]);
soapMessageWriter.Write(soapEnvHeaderString3);
// End clubbing of baby seals
// Add the soapBodyString back in - it's got all the closing XML we need.
//soapBodyString = dammit;
soapMessageWriter.Write(soapBodyString);
// write it all out.
soapMessageWriter.Flush();
appOutputStream.Flush();
appOutputStream.Position = 0;
StreamReader reader = new StreamReader(appOutputStream);
StreamWriter writer = new StreamWriter(this.outputStream);
writer.Write(reader.ReadToEnd());
writer.Flush();
appOutputStream.Close();
this.outgoing = false;
this.incoming = true;
break;
}
case SoapMessageStage.BeforeDeserialize:
{
//Make the output available for the client to parse...
readStr = new StreamReader(oldStream);
writeStr = new StreamWriter(newStream);
soapMsg1 = readStr.ReadToEnd();
xDoc.LoadXml(soapMsg1);
soapMsg1 = xDoc.InnerXml;
writeStr.Write(soapMsg1);
writeStr.Flush();
newStream.Position = 0;
break;
}
case SoapMessageStage.AfterDeserialize:
break;
default:
throw new Exception("invalid stage!");
}
}
}
Add following to web.config
<system.web>
<webServices>
<soapExtensionTypes>
<add type="TDCWS.WSHeader,TDCWS" priority="1" group="Low"/>
</soapExtensionTypes>
</webServices>
</system.web>
Hope that can help!
References:
No comments:
Post a Comment