SOAP web services and NAV restrictions

Cem_KaraerCem_Karaer Member Posts: 281
Hello,
I have to find a way to consume 3rd party web services within NAV classic clients (5.0 to 2009). I found no mention of WCF usage within NAV in neither this forum nor anywhere else. So I decided to create proxy SOAP services first and then consume those services in NAV. I did consume SOAP web services thanks to the following entry:

http://www.mibuso.com/forum/viewtopic.php?f=23&t=1303

First I manually created the SOAP body, and use soap serializer's WriteXml functions. But here came the NAV limitation: can't use strings longer than 1024..

So I changed my mind and use serializer's StartElement, WriteString and EndElement functions. It did work well but.. I had to elaborate my code according to the structure of proxy services' web methods.

Then I changed my mind again and attempted to use XMLPorts. I thought that something with XML would be great for another thing based on XML. So I designed XMLPorts that can produce the exact response XML documents. But here came another obstacle: I can't use that beautiful XML with httpconnector (which is mentioned in the link)..

So I changed my mind again :) and use XMLHTTP with open, setRequestHeader and send functions. It was really great until I collided to the same NAV limitation: can't use string longer than 1024 in the send() function.

What is the best way? Should I elaborate my code for each and every method or try to find a way for using the output of XMLPorts.

Note: The best way is to upgrade to 2013 and use RTC, but it is not possible for non-technical reasons.
Cem Karaer @ Pargesoft
Dynamics NAV Developer since 2005

Comments

  • njhansennjhansen Member Posts: 36
    We had a similar situation on site (NAV 2009), and after a fair bit of trying and retrying, we decided to just write C# code to actually talk to the third party WS, and put it into a DLL that NAV could use as an automation object.

    Two potential problems (aside from the obvious required experience with C# and writing automations):
    1) The DLL needs to be deployed to every classic client machine that might use the WS
    2) The automation references get confused if you recompile your DLL and let the compiler assign different GUIDs to your functions. Make sure that you manually assign GUIDs, and as much as possible, only add new functions to the end of your classes (which is abhorrent to people who like their code organized nicely, but better than having your NAV code calling random interfaces).

    Once you are dealing with a COM interface for which you can define the parameters, you can work around most of the NAV restrictions by changing the interfaces a bit -- for example, if you really do need to read a single huge text field into NAV, you can define an interface that hands it to you in 1024 byte chunks.
  • vaprogvaprog Member Posts: 1,116
    I suggest you create your XML (SOAP Envelope including Body contents as a MSXML DomDocument Then use
    XMLHTTP.Send(DOMDocument.xml)
    
    to send the request. Alternatively you may just construct the SOAP Body as a DOMDocument and use it like
    XMLHTTP.send(
      '<?xml version="1.0" encoding="UTF-8"?>'+
      '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">' +
        '<soapenv:Header/>'+
        '<soapenv:Body>'+
          XMLDocument.xml+
        '</soapenv:Body>'+
      '</soapenv:Envelope>');
    
  • Cem_KaraerCem_Karaer Member Posts: 281
    vaprog wrote:
    I suggest you create your XML (SOAP Envelope including Body contents as a MSXML DomDocument Then use
    XMLHTTP.Send(DOMDocument.xml)
    
    to send the request. Alternatively you may just construct the SOAP Body as a DOMDocument and use it like

    Hello vaprog,

    I exactly use that manner. But at that point NAV gives string restriction error.

    I think it is the most viable solution to create and use automation objects as hjhansen suggests for versions below 2009. For 2009 classic client, I think to consume 3rd party WS in a separate codeunit by using DotNet proxy dll and publish this codeunit as NAV's WS, guaranteeing the function parameter clarity. Because the published codeunit will be run on the server side, using dotNet variables will not be a problem. Then I can consume that NAV's web service within the classic client in a much more simple way.

    I hope I am not wrong?
    Cem Karaer @ Pargesoft
    Dynamics NAV Developer since 2005
  • Cem_KaraerCem_Karaer Member Posts: 281
    Hello all,

    I successfully created a proxy dotNET dll for calling WS as described follows:

    http://dynamicsuser.net/blogs/waldo/archive/2011/12/20/net-interop-consume-a-third-party-web-service-check-vat-registration-no.aspx

    But one more problem happened when I used dll in C/AL. The reason of the problem is described below:

    http://stackoverflow.com/questions/352654/could-not-find-default-endpoint-element

    The solution for this problem is to copy and paste the content of the config file of proxy dll into the Microsoft.Dynamics.Nav.Server.exe.config file located under the service folder of NAV. Just copy-pasting the dll and its config file to the Add-ins folder isn't enough because NAV server executable (Microsoft.Dynamics.Nav.Server.exe) looks for necessary endpoint configuration in its configuration file, not dll's.
    Cem Karaer @ Pargesoft
    Dynamics NAV Developer since 2005
  • Cem_KaraerCem_Karaer Member Posts: 281
    Hello,

    I have one little rough to rasp:

    When I use WCF classes as dotNet variables, nullable variables get following form:
    System.Nullable`1
    

    I figured out no way to assign any value to that kind of class property. How can I set a nullable property of a dotNet variable?
    Cem Karaer @ Pargesoft
    Dynamics NAV Developer since 2005
  • Cem_KaraerCem_Karaer Member Posts: 281
    Hello,

    As the following entry shows, there is no way to do this :(:(

    http://mibuso.com/forum/viewtopic.php?f=32&t=58529&hilit=nullable
    Cem Karaer @ Pargesoft
    Dynamics NAV Developer since 2005
  • vaprogvaprog Member Posts: 1,116
    cemkaraer wrote:
    Hello vaprog,
    I exactly use that manner. But at that point NAV gives string restriction error.
    Ok, I See. My code appears to work on middle tier, but not on classic.
    Here's how I did it for classic:
    VAR
      XMLDocRequest@1100118020 : Automation 'Microsoft XML, v6.0'.DOMDocument60;
      XMLSOAP : Automation 'Microsoft XML, v6.0'.DOMDocument60;
      TempBlob : Record 99008535;
      OutStrm : OutStream;
      InStrm : InStream;
    
    ...
      
    EnvelopeSOAPRequest(XMLRequest,XMLSOAP);
    TempBlob.Blob.CREATEOUTSTREAM(OutStrm);
    XMLSOAP.save(OutStrm);
    TempBlob.Blob.CREATEINSTREAM(InStrm);
    XmlHttp.send(InStrm);
    CLEAR(OutStrm);
    CLEAR(InStrm);
    CLEAR(TempBlob);
    
    PROCEDURE EnvelopeSOAPRequest(
      VAR Request : Automation 'Microsoft XML, v6.0'.DOMDocument60;
      VAR SOAP : Automation 'Microsoft XML, v6.0'.DOMDocument60);
    VAR
      BodyElement : Automation 'Microsoft XML, v6.0'.IXMLDOMNode;
      NewNode : Automation 'Microsoft XML, v6.0'.IXMLDOMNode;
      DocFragment : Automation 'Microsoft XML, v6.0'.IXMLDOMDocumentFragment;
    BEGIN
      // places Request DOM in SOAP envelope's Body element
      // returns resulting DOM in VAR parameter SOAP
      CLEAR(SOAP);
      CREATE(SOAP);
      SOAP.loadXML(
        '<?xml version="1.0" encoding="UTF-8"?>'+
        '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">' +
          '<soapenv:Header/>'+
          '<soapenv:Body>'+
          '</soapenv:Body>'+
        '</soapenv:Envelope>');
      SOAP.setProperty('SelectionNamespaces','xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"');
      BodyElement := SOAP.selectSingleNode('/s:Envelope/s:Body');
      NewNode := Request.documentElement;
      NewNode := SOAP.importNode(NewNode,TRUE);
      NewNode := BodyNode.appendChild(NewNode);
    END;
    

    It might be easier to construct the request withing the envelope's body element from the beginning rather than adding the envelope later.

    The main part, though, is to use streams instead of strings.
Sign In or Register to comment.