Skip to main content

Notifications

Announcements

No record found.

Community site session details

Community site session details

Session Id :
Customer experience | Sales, Customer Insights,...
Suggested answer

SOAP Extension - .SOAP Extension is throwing NullReferenceException inside inside the D365 plugin

(0) ShareShare
ReportReport
Posted on by 55

Hello Experts,

We have recently implemented the SOAP Extension within Plugin and getting the below exception and the same code is working fine in the Console Application.

I cannot debug the plugin code and the plugin registration tool is restricting debug since it's an external call. when I do any update on the plugin (just commenting one line of code) then gave me this exception and earlier it was working fine.

Please suggest the same.

Error occured in ExecuteCrmPlugin in CallSOAPService class: System.NullReferenceException: Object reference not set to an instance of an object.
at D365.Plugins.CallSOAPService .SoapReverserExtension.ProcessMessage(SoapMessage message)
at System.Web.Services.Protocols.SoapMessage.RunExtensions(SoapExtension[] extensions, Boolean throwOnException)
at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
at D365.Plugins.objSOAPCall.SoapOp(IPackets pPacketsIn)

Thanks

-Sri

Categories:
  • Singapuram Profile Picture
    55 on at
    RE: SOAP Extension - .SOAP Extension is throwing NullReferenceException inside inside the D365 plugin

    Thanks, Guido for your response, It seems to be SoapMessage object is not completely initialized at the BeforeDeserialize stage. Both the Action and MethodInfo properties throw errors at this stage.

    Is there any way to log the details using plugin trance log since SOAP header authentication logic is in a different class (ReverserExtensionAttribute) and the ProcessMessage method will get invoked when we call the xiPayWorkerObj.SoapOp()

    It appears the correct order is:

    BeforeDeserialize

    a. Read Server URL

    b. Retrieve request information (certificates, user host address, etc.)

    c. Read request contents from stream

    AfterSerialize

    a. Read Exceptions

    b. Read MethodInfo information (and Action information if necessary)

    c. Read response contents from stream

    Thanks

    -Sri

  • Guido Preite Profile Picture
    54,057 Moderator on at
    RE: SOAP Extension - .SOAP Extension is throwing NullReferenceException inside inside the D365 plugin

    the code you posted is not complete or is not the part of a Dynamics plugin (the interface IPlugin is missing and the implementation of the Execute method).

    However inside this code there are several libraries used (like System.Reflection or System.IO) that can cause an issue when running inside a plugin. (is a possibility, not a sure thing)

    My suggestion is to move the code to be executed inside an external service (like an Azure function) called by the plugin.

    hope it helps

  • Suggested answer
    Singapuram Profile Picture
    55 on at
    RE: SOAP Extension - .SOAP Extension is throwing NullReferenceException inside inside the D365 plugin

    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
    }
    }

  • Guido Preite Profile Picture
    54,057 Moderator on at
    RE: SOAP Extension - .SOAP Extension is throwing NullReferenceException inside inside the D365 plugin

    the error "Object reference not set to an instance of an object." usually means that a value is null and you are not checking that is null (like a lookup or an optionset)

    check the source code and make sure you are checking for null values before accessing them

    hope it helps

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Dynamics 365 Community Update – Sep 16th

Welcome to the next edition of the Community Platform Update. This is a weekly…

Announcing Our 2024 Season 2 Super Users!

A new season of Super Users has arrived, and we are so grateful for the daily…

Dynamics 365 Community Newsletter - September 2024

Check out the latest community news

Leaderboard

#1
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 283,860 Test role Public

#2
Ludwig Reinhard Profile Picture

Ludwig Reinhard Microsoft Employee

#3
Martin Dráb Profile Picture

Martin Dráb 225,155 Moderator

Leaderboard

Featured topics

Product updates

Dynamics 365 release plans