Thanks, Guido, The exception which I am receiving from the Process Message -SOAP Extension which I am unable to debug and I update anything to the plugin (Ex: with a simple commented line) it's not working.
Here is the code which I am registering the SOAP Extension programmatically and Class file.
Type t = typeof(Demo.D365.Plugins.SoapAuthentication.SoapReverserExtension);
RegisterSoapExtension(t, 1, PriorityGroup.High);
[ReflectionPermission(SecurityAction.Demand, Unrestricted = true)]
public static void RegisterSoapExtension(Type type, int priority, PriorityGroup group)
{
if (!type.IsSubclassOf(typeof(SoapExtension)))
{
throw new ArgumentException("Type must be derived from SoapException.", "type");
}
if (priority < 1)
{
throw new ArgumentOutOfRangeException("priority", priority, "Priority must be greater or equal to 1.");
}
// get the current web services settings...
WebServicesSection wss = WebServicesSection.Current;
// set SoapExtensionTypes collection to read/write...
FieldInfo readOnlyField = typeof(System.Configuration.ConfigurationElementCollection).GetField("bReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
readOnlyField.SetValue(wss.SoapExtensionTypes, false);
// inject SoapExtension...
//wss.SoapExtensionTypes.Add(new SoapExtensionTypeElement(type, priority, group));
SoapExtensionTypeElement soapInterceptor = new SoapExtensionTypeElement();
soapInterceptor.Type = type;
soapInterceptor.Priority = priority;
soapInterceptor.Group = group;
wss.SoapExtensionTypes.Add(soapInterceptor);
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services.Protocols;
using System.Reflection;
using System.IO;
using System.Xml;
namespace TG.D365.Plugins.SoapAuthentication
{
public enum SOAPMessageType
{
Request, Response
}
public class LoggingException
{
public static string[] Ignore = new string[] { "com.qas.proweb.soap.ProWeb", "SalesInterface.Services.OrderQueueClient", "SalesInterface.Services.OlympusAdminSvc" };
}
[AttributeUsage(AttributeTargets.Method)]
public class SoapReverserExtensionAttribute : SoapExtensionAttribute
{
public override Type ExtensionType
{
get { return typeof(SoapReverserExtension); }
}
private int priority = 1;
public override int Priority
{
get
{
return priority;
}
set
{
priority = Priority;
}
}
}
public class SoapReverserExtension : SoapExtension
{
private Stream oldStream;
private Stream newStream;
private string ServiceName;
private string MethodName;
public string FullName
{
get
{
if (string.IsNullOrWhiteSpace(ServiceName))
{
return string.IsNullOrWhiteSpace(MethodName) ? "Unknown" : MethodName;
}
else
{
return ServiceName + " " + MethodName;
}
}
}
private static XmlDocument xmlRequest;
/// <summary>
/// Gets the outgoing XML request
/// </summary>
public static XmlDocument XmlRequest
{
get { return xmlRequest; }
}
private static XmlDocument xmlResponse;
/// <summary>
/// Gets the incoming XML response
/// </summary>
public static XmlDocument XmlResponse
{
get { return xmlResponse; }
}
/// <summary>
/// Save the Stream representing the SOAP request
/// or SOAP response into a local memory buffer.
/// </summary>
/// <param name="stream"></param>
/// <returns></returns>
public override Stream ChainStream(Stream stream)
{
oldStream = stream;
newStream = new MemoryStream();
return newStream;
}
/// <summary>
/// If the SoapMessageStage is such that the SoapRequest or
/// SoapResponse is still in the SOAP format to be sent or received,
/// save it to the xmlRequest or xmlResponse property.
/// </summary>
/// <param name="message"></param>
public override void ProcessMessage(SoapMessage message)
{
//jsmdirect url comes from mission ws.
if (message.Url.Contains("jsmdirect") && isMissionDown())
{
//cancel mission webservice call
SoapClientMessage call = message as SoapClientMessage;
try
{
call.Client.Abort();
}
catch (Exception ex)
{
//Logs.InsertLog("Party Search", "Error Service TGMissionWS.", ex);
}
}
else
{
switch (message.Stage)
{
case SoapMessageStage.BeforeSerialize:
break;
case SoapMessageStage.AfterSerialize:
// XiPay needs WAS Address Enabled
if (message.Url.Contains("XiPay30WS"))
{
{
SoapClientMessage scm = message as SoapClientMessage;
XiPayWS xpw = scm.Client as XiPayWS;
System.Net.NetworkCredential nc = xpw.Credentials as System.Net.NetworkCredential;
xmlRequest = RewriteRequestWithWSA(nc.Domain, nc.UserName, nc.Password, xpw.Url);
}
}
else
{
// Normal Handling
xmlRequest = GetSoapEnvelope(newStream);
CopyStream(newStream, oldStream);
}
if (!LoggingException.Ignore.Contains(ServiceName))
{
//SalesInterface.Models.Logs.InsertLog("Request" + (string.IsNullOrWhiteSpace(MethodName) ? "" : MethodName), FullName, xmlRequest.OuterXml);
}
break;
case SoapMessageStage.BeforeDeserialize:
CopyStream(oldStream, newStream);
xmlResponse = GetSoapEnvelope(newStream);
if (!LoggingException.Ignore.Contains(ServiceName))
{
//SalesInterface.Models.Logs.InsertLog("Response" + (string.IsNullOrWhiteSpace(MethodName) ? "" : MethodName), FullName, xmlResponse.OuterXml);
}
break;
case SoapMessageStage.AfterDeserialize:
// WSA Addressing response requires us to Understand their response header.
if (message.Url.Contains("XiPay30WS"))
{
if (message.Headers.Count > 0)
{
for (int cntHeader = 0; cntHeader < message.Headers.Count; cntHeader++)
{
if (message.Headers[cntHeader].MustUnderstand)
{
message.Headers[cntHeader].DidUnderstand = true;
}
}
}
}
break;
}
}
}
private bool isMissionDown()
{
Boolean isDown = false;
//using (svm_dev_olympusEntities entity = new svm_dev_olympusEntities())
//{
// //CacheHelper.GetCacheValue("IsMissionDown", out isDown);
// if (!CacheHelper.GetCacheValue("IsMissionDown", out isDown))
// {
// //Retrieve value from database
// string isMissionDown =
// (from ms in entity.ApplicationSettings
// where ms.Name == "IsMissionDown"
// select ms.Value).SingleOrDefault();
// bool.TryParse(isMissionDown, out isDown);
// CacheHelper.SaveCacheValue("IsMissionDown", isDown, 5);
// }
//}
return isDown;
}
/// <summary>
/// Returns the XML representation of the Soap Envelope in the supplied stream.
/// Resets the position of stream to zero.
/// </summary>
/// <param name="stream"></param>
/// <returns></returns>
private XmlDocument GetSoapEnvelope(Stream stream)
{
XmlDocument xml = new XmlDocument();
stream.Position = 0;
StreamReader reader = new StreamReader(stream);
xml.LoadXml(reader.ReadToEnd());
stream.Position = 0;
return xml;
}
/// <summary>
/// Copies a stream.
/// </summary>
/// <param name="from"></param>
/// <param name="to"></param>
private void CopyStream(Stream from, Stream to)
{
TextReader reader = new StreamReader(from);
TextWriter writer = new StreamWriter(to);
writer.WriteLine(reader.ReadToEnd());
writer.Flush();
}
private XmlDocument RewriteRequestWithWSA(string hdrWSA_Domain, string hrdWSA_UserName, string hrdWSA_pwd, string hrdWSA_URL)
{
string soapRequestMsg;
XmlDocument xmlDoc = new XmlDocument();
XmlDocument xmlDocCleanForLogging = new XmlDocument();
newStream.Position = 0;
var streamReader = new StreamReader(newStream);
var streamWriter = new StreamWriter(oldStream);
soapRequestMsg = streamReader.ReadToEnd();
xmlDoc.LoadXml(soapRequestMsg);
//****************
//Add some namespaces to the envelope
var envNode = xmlDoc.GetElementsByTagName("soap:Envelope")[0];
XmlAttribute attrWsse = xmlDoc.CreateAttribute("xmlns:wsse");
attrWsse.InnerText = "">docs.oasis-open.org/.../oasis-200401-wss-wssecurity-secext-1.0.xsd";
envNode.Attributes.Append(attrWsse);
XmlAttribute attrWsu = xmlDoc.CreateAttribute("xmlns:wsu");
attrWsu.InnerText = "">docs.oasis-open.org/.../oasis-200401-wss-wssecurity-utility-1.0.xsd";
envNode.Attributes.Append(attrWsu);
//XmlAttribute attrns1 = xmlDoc.CreateAttribute("xmlns:ns1");
//attrns1.InnerText = "">">">http://Paymetric/XiPaySoap30";
//envNode.Attributes.Append(attrns1);
//XmlAttribute attrns2 = xmlDoc.CreateAttribute("xmlns:ns2");
//attrns2.InnerText = "">Paymetric/.../";
//envNode.Attributes.Append(attrns2);
// ****
// Body
//var bodyNode = xmlDoc.GetElementsByTagName("Body", "">www.w3.org/.../")[0];
var bodyNode = xmlDoc.GetElementsByTagName("soap:Body")[0];
// ****
// Header
//var headerNode = xmlDoc.CreateElement("s", "Header", "">www.w3.org/.../");
var headerNode = xmlDoc.CreateElement("soap", "Header", "">schemas.xmlsoap.org/.../");
XmlAttribute attrWsa = xmlDoc.CreateAttribute("xmlns:wsa");
attrWsa.InnerText = "">www.w3.org/.../addressing";
headerNode.Attributes.Append(attrWsa);
// Security Node
var security = xmlDoc.CreateElement("wsse", "Security", "">docs.oasis-open.org/.../oasis-200401-wss-wssecurity-secext-1.0.xsd");
// Username token
var usernameToken = xmlDoc.CreateElement("wsse", "UsernameToken", "">docs.oasis-open.org/.../oasis-200401-wss-wssecurity-secext-1.0.xsd");
// Username
var userName = xmlDoc.CreateElement("wsse", "Username", "">docs.oasis-open.org/.../oasis-200401-wss-wssecurity-secext-1.0.xsd");
userName.InnerText = hdrWSA_Domain + "\\" + hrdWSA_UserName;
// pwd
var password = xmlDoc.CreateElement("wsse", "Password", "">docs.oasis-open.org/.../oasis-200401-wss-wssecurity-secext-1.0.xsd");
password.InnerText = hrdWSA_pwd;
XmlAttribute attrPwd = xmlDoc.CreateAttribute("Type");
attrPwd.InnerText = "">docs.oasis-open.org/.../oasis-200401-wss-username-token-profile-1.0
password.Attributes.Append(attrPwd);
// Add the elements
usernameToken.AppendChild(userName);
usernameToken.AppendChild(password);
security.AppendChild(usernameToken);
headerNode.AppendChild(security);
// Add Action
var actionNode = xmlDoc.CreateElement("wsa", "Action", "">www.w3.org/.../addressing");
//XmlAttribute mustUnder = xmlDoc.CreateAttribute("mustUnderstand");
//mustUnder.InnerText = "1";
//actionNode.Attributes.Append(mustUnder);
actionNode.InnerText = "Paymetric/XiPaySoap30/action/XiGGE.SoapOp";
headerNode.AppendChild(actionNode);
// Add WAS To...
var toNode = xmlDoc.CreateElement("wsa", "To", "">www.w3.org/.../addressing");
toNode.InnerText = hrdWSA_URL;
headerNode.AppendChild(toNode);
// Add the new header just before the body.
bodyNode.ParentNode.InsertBefore(headerNode, bodyNode);
soapRequestMsg = xmlDoc.InnerXml;
streamWriter.Write(soapRequestMsg);
streamWriter.Flush();
// We need to remove our username and pwd from logging...
xmlDocCleanForLogging.InnerXml = xmlDoc.InnerXml;
var cleanUsernameNode = xmlDocCleanForLogging.GetElementsByTagName("wsse:Username")[0];
cleanUsernameNode.InnerText = "-removed-";
var cleanPwdNode = xmlDocCleanForLogging.GetElementsByTagName("wsse:Password")[0];
cleanPwdNode.InnerText = "-removed-";
return xmlDocCleanForLogging;
}
#region NoOp
/// <summary>
/// Included only because it must be implemented.
/// </summary>
/// <param name="methodInfo"></param>
/// <param name="attribute"></param>
/// <returns></returns>
public override object GetInitializer(LogicalMethodInfo methodInfo,
SoapExtensionAttribute attribute)
{
MethodName = methodInfo.Name;
return null;
}
/// <summary>
/// Included only because it must be implemented.
/// </summary>
/// <param name="WebServiceType"></param>
/// <returns></returns>
public override object GetInitializer(Type WebServiceType)
{
return WebServiceType.FullName;
}
/// <summary>
/// Included only because it must be implemented.
/// </summary>
/// <param name="initializer"></param>
public override void Initialize(object initializer)
{
ServiceName = (string)initializer;
}
#endregion
}
}