Web Services Black Belt: consuming NAV web services using pure C/AL

MP900406779[1]Have you ever needed to connect to the Web services of one NAV instance from another one? If so, I bet that the approach was something like this: you created a .NET class where you defined a Web or Service reference to the target instance, and then you consumed that .NET class using .NET Framework interoperability. It was kind of clumsy, inflexible, but it worked.

How cool would it be if you could do something like this:

WITH WebService DO BEGIN
  CONNECT(‘http://localhost:7047/DynamicsNAV70/WS/CRONUS%20International%20Ltd/Page/Customer’);

  INIT;
  SETVALUE(‘Name’,’Test Customer’);
  SETVALUE(‘Blocked’,Cust.Blocked::Ship);
  SETVALUE(‘Credit_Limit_LCY’,10000);
  CREATE;

  MESSAGE(‘I just created Customer No. %1 in another NAV instance.’,GETVALUE(‘No’));
END;

As a matter of fact, you can write something like that. You can write exactly that. And it compiles, runs, and accomplishes exactly what you expect it to do. The most beautiful thing, you don’t need to write a single line of code in Visual Studio, or deploy any external dependencies – it uses pure C/AL, and works equally well in NAV 2009 and NAV 2013.

The only thing you need is a simple codeunit that you can download from Mibuso. If you missed the link in the previous sentence, then click here.

I wrote that codeunit as a part of the demo I presented last Wednesday at Mibuso NAV TechDays 2012 in Antwerp, and as promised – I am making the code available for you to use.

This simple codeunit does no magic, it simply harnesses the power of the features built into the .NET Framework. It builds the proxy class and compiles it on the fly, and then uses reflection to instantiate objects, set properties, and call methods to allow you to interact with any NAV page web service.

Before you can consume a NAV page Web service from C/AL you do not need to know anything about the service, except for its URL. If it’s a page web service, you can use it to read, create, update, and delete data in another NAV instance, simply using C/AL.

At this stage, it supports the following page web service functions:

  • Read
  • ReadMultiple
  • Create
  • CreateMultiple
  • Update
  • UpdateMultiple
  • Delete

Right now, I am providing no documentation for it, but I believe it should not be difficult to figure out what it can do by following these couple of examples.

Creating a customer

That’s the example above. Just declare a variable named WebService of type Codeunit 50113, and you are good to go.

Iterating through a set of customers read, with a filter applied

WITH WebService DO BEGIN
  CONNECT(‘http://localhost:7047/DynamicsNAV70/WS/CRONUS%20International%20Ltd/Page/Customer’);
  SETFILTER(‘Balance_LCY’,’>0′);
  SETFILTER(‘Name’,’A*’);
  IF READMULTIPLE THEN
    REPEAT
      MESSAGE(‘Customer %1 %2 has balance of %3’,GETVALUE(‘No’),GETVALUE(‘Name’),GETVALUE(‘Balance_LCY’));
    UNTIL NEXT = 0;
END;
EXIT;

Updating an item

WITH WebService DO BEGIN
  INIT;
  SETVALUE(‘No’,’1000’);
  READ;
  SETVALUE(‘Description’,’Bicycle 2’);
  UPDATE;
END;

Creating a purchase order from a sales order

WITH WebService DO BEGIN
  CONNECT(‘http://localhost:7047/DynamicsNAV70/WS/CRONUS%20International%20Ltd/Page/PurchOrder’);
  INIT;
  SETVALUE(‘Buy_from_Vendor_No’,Rec."Sell-to Customer No.");
  SalesLine.SETRANGE("Document Type",Rec."Document Type");
  SalesLine.SETRANGE("Document No.",Rec."No.");
  IF SalesLine.FINDSET THEN
    REPEAT
      NEWLINE;
      SETLINEVALUE(‘Type’,FORMAT(SalesLine.Type));
      SETLINEVALUE(‘No’,FORMAT(SalesLine."No."));
      SETLINEVALUE(‘Quantity’,SalesLine.Quantity);
    UNTIL SalesLine.NEXT = 0;
  CREATE;
  MESSAGE(‘Purchase Order No. %1 is created in the vendor”s system.’,GETVALUE(‘No’));
END;

I’ll be updating the functionality of this codeunit and uploading a more comprehensive version, as I find time to do this.

This post is a series of posts where I’ll present most of the stuff I talked about at NAV TechDays 2012, and expand those topics into the areas that I either had to leave out due to time constraints, or that I thought were not as interesting as those that I chose to put into the presentation.

Please, let me know how you like this small gadget.

Vjeko

Vjeko has been writing code for living since 1995, and he has shared his knowledge and experience in presentations, articles, blogs, and elsewhere since 2002. Hopelessly curious, passionate about technology, avid language learner no matter human or computer.

This Post Has 142 Comments

  1. Tarek Demiati

    Where can we Get Codeunit 50113 and the source code of the Visual Studio project you’ve implemented during the NAV Tech Days.

    1. Vjekoslav Babic

      @Tarek – I’ve uploaded it on Mibuso, and as soon as they approve the upload, I’ll link it from the blog post. You won’t miss it. Regarding the Visual Studio project, I’ll make a couple of blog posts around that, too, so stay tuned.

      1. Senthil

        How to update Multiple Line Records, will it work using UPDATE function. Expecting quick reply .. thanks

        1. Vjeko

          Well, if you can do it with page web service proxy class in C#, you can do it here. I don’t think I specifically implemented support for assigning values to lines, but it shouldn’t be a difficult thing to do.

      2. Mohamed Zayed

        Hi Vjekoslav,
        I have a compile error in the CU, The system canot find table “WebServicesSetup”? is this is a new table? should I create it ? or how can I solve this issue?

        Thanks alot,
        Zayed

        1. Vjeko

          You need to create this table. It contains credentials to connect, and from code you have it’s obvious what this table should look like. What it achieves is that it stores the credentials. Just figure your own way how to store and pass credentials to the web service and you are good to go.

  2. Erik

    You started obviously developing from c# to NAV? Doesn’t matter of course and your way of thinking is giving me new ideas how to look at NAV. Excellent.

    Didn’t see a VS project. More ideas?

    1. Vjekoslav Babic

      Erik: at first I did indeed develop this thing in C#, and then moved it to C/AL, but now it is pure C/AL and no C# at all. There is no VS project. Which VS project are you referring to?

  3. Erik

    Tarek is mentioning this “…and the source code of the Visual Studio project..”.

    Would you mind sharing the C# version. I love this reflection. You don’t need to document it, just the functions is enough so I can start the debugger to understand it.

  4. Ryan

    Hi,

    Is this Codeunit the (fob and txt) only compatible with NAV2013.

    As I cant import it into a NAV2009 R2 Database.

  5. Erik

    Short bump.. and have the same problem with 2009. And why am i looking so sad?

    1. Vjekoslav Babic

      Okay, okay, 🙂 I’ll catch some time to prepare a NAV2009 verified bersion and to post the C# version. Weekend looks likely.

  6. Daniel Lee

    Excellent.

  7. Fred

    I just imported the NAV 2009 code, but when I call it an error message “The DotNet variable has not been instantiated.” pops up. I traced it back to the line:
    ——
    AssemblyReferences := AssemblyReferences.CreateInstance(DotNetType.GetType(‘System.String’),2);
    ——
    Any suggestions how to fix this?

    1. Vjekoslav Babic

      Fred: I don’t know, but I suspect it may be due to the hotfix that you are using. I’ve used the last one, and I did compile and test before releasing. For last hotfix for NAV 2009 R2, check Waldo’s blog at http://www.waldo.be/

  8. Matthias

    Hi Fred

    just want to confirm Vjekoslav solution.
    Thanks Vjekoslav for the solution.

    i had problems using it in NAV 2009 R2 (Build 32012).
    With NAV 2009 R2 Build 33053 the example of Vjekoslav works fine.

  9. Roy

    Hi Fred,

    Thanks for your great work, however, here is an error due to missing of the Table123456701 at the last function – Authenticate in the object.

    Would you be so kind to release the table for us?
    Thank you very much!

    1. Vjekoslav Babic

      @Roy: Who’s Fred? My name is Vjeko, nice to meet you 🙂 I can’t check this thing about Table 123456701, but I am pretty sure it’s a rogue variable declaration, and that you can safely skip it, but I’ll do a check on my earliest.

      1. Pauli

        Hi.
        A table that is referencend and used in function Authenticate is missing. Variable name is WebServicesSetup and it refers to table 123456701. One could easily remove the variable and insert the values for user name and pwd hard coded, but just to let you know:

        WITH WebServicesSetup DO BEGIN
        IF GET THEN
        ServiceInstance.Credentials := Credential.NetworkCredential(“User Name”,Password)

        /Pauli

        1. Vjeko

          @Pauli: thanks for the comment. Yes – I am aware of that, but it can be easily figured out from the code what fields this table should contain. Or – you can do a quick fix that you did.

  10. Roy

    Hi Fred,

    Another question is, is your solution compatible with https ?
    i just try to use it for calling web service with SSL, but it failed.

    Thanks!

    1. Bartosz

      Hi Vjeko,

      I also tried to use this solution with SSL but it failed.
      Do you know how to connect to web service with SSL?

      Thanks in advance.

  11. Tom Hunt

    I’ve used this and it works very well for NAV 2009. Thanks for putting it together! It has some issues with NAV 2013 relating to the XML-consumption objects, though. Someday, maybe I’ll try and figure out how to do it in 2013 and do a write-up on it.

    1. Vjeko

      Strange, it should work better with 2013, because it provides better interoperability with .NET. I’ll really have to take a look and figure it out, but if you can also be more specific as to what doesn’t work well, it would help a lot.

  12. Roger Larsson

    Very nice work! I was blown away when you showed us at NavTechDays2012. The compile in memory could be used whenever a need for a new component is required.

  13. Gert Lynge

    “It helped” (requirements for your webservice CU hereby met :-)). Thank you for your great Work.
    Regards
    Gert Lynge

    1. Vjeko

      Thanks, Gert! Much appreciated! Good luck with it and leave some feedback in the future.

  14. Roberto Stefanetti

    hi Vjeko,
    excellent and ingenious tool, we are using it and it works fine on NAV 2009 & 2013.
    Great!

    Some questions please:
    – would be possible in addition to the pages, you can also invoke codeunits published as Web Services?
    for now, Iiput a function in the page that in the “Onload of the page” trigger, lanches the codeunit.

    – it would be possible to extend the existing functionalities, inserting calls (Invokes) in codeunit and xmlports?

    Thanks for support
    Roberto

    1. Vjeko

      Roberto – it could be possible, yes. Codeunits for certain, XMLports would also be possible bu more complicated and less intuitive to work with from C/AL. I’ll see if I have time to continue working on this tool.

      1. Eddy

        hi Vjeko, Do the CodeUnits functions for Webservice work from C/AL already available ?

  15. Martin Hansen

    “It helped” 🙂
    It helped a lot in fact! Thank you for making this awesome tool available to all of us. I was just about to ask the same question as Roberto regarding codeunits, but I see that you have already answered that one. Hope you find time to extend the functionality.
    Thanks again
    Martin

  16. vanAnaarB

    Great stuff works like a charm. UseDefaultCredentials didn’t work for me while being on a local server. So i used:

    //WITH WebServicesSetup DO BEGIN
    // IF GET THEN
    ServiceInstance.Credentials := Credential.NetworkCredential(‘john’,’1234′);
    // ELSE
    // ServiceInstance.UseDefaultCredentials := TRUE;
    //END;

    1. Vjeko

      @vanAnaarB: You could have simply supplied username and password into the Web Service Setup table. But still, I am glad the code helped! Good luck with it!

  17. Karan

    hey i want to delete Sales Order and line from Navision 2013 using web services in C#.net,
    how will i use delete according to my filter
    plz tell me

    Thanks in advance

    1. Vjeko

      @Karan: I don’t quite understand what exactly you want to achieve? If you want to delete Sales Order AND line – then it is enough to delete the Sales Order, and all its lines are deleted. If you want to delete a single line for a sales order, then you must call the Delete_SalesLines method on the web service. You must pass the Key parameter to it, and you can read the key from each of the lines in the Sales Order. You can find these in the SalesLines property of the sales order entity.

  18. Damian

    Hello,
    I have a small problem with this code. I described it here
    http://mibuso.com/forum/viewtopic.php?f=7&t=55040

    But I need to run it on Windows Server 2012 R2. I checked this code on Windows Server 2008 and it works fine. The version of .NET Framework is the same. I’ve heard that in 2012 R2 handling of XML is changed. Maybe this is the cause of the problem?
    Could you help me with this?
    I would be very thankful.

    Thanks in advance

    1. Vjeko

      @Damian: can you please let me know which page web service are you trying to access, when you get this parameter count mismatch error? It should have nothing to do with the handling of XML. Also, if you can provide the whole WSDL document of that page, as well as the page object exported as a text file, it would help. I suspect that this is a Worksheet page, or some other page where you have added some field controls above the topmost group control.

      1. Damian

        Thank you for the fast reply. I sent you everything in e-mail. If you could help me, it would be great.

        1. Vjeko

          @Damian: Well, just as I suspected – the metadata in the page is not correct. For web services to work correctly, you must put all the field controls into a Group control (a FastTab). If you just dump them into the ContentArea, then web services sees each of the fields as a parameter of all service methods for the web service, and my generic web service management code cannot work with that. So – to fix this, just add a Group just below the ContentArea and above the first Field, and then indent all the fields under the group, and it should magically work 🙂

          1. Damian

            It works, just perfect!!! 🙂 Thank you so much. It is not my page, so I didn’t notice that there is no grup inside. Thanks once again.

  19. Damian

    Hi,

    I have another question. When I try to update one field, I get a message: “A DotNet variable has not been instantiated. Attempting to call System.Reflection.MethodInfo.GetParameters in CodeUnit Generic Web Service Client: UPDATE”. It occurs in this line: “Parameters := Parameters.CreateInstance(GETDOTNETTYPE(Object),_Create.GetParameters().Length);”. I use your code for updating. Do you know the solution?
    Thanks for support.
    Damian

    1. Damian

      Hello,
      I would be thankful for your help.
      Thank you

      1. Vjeko

        @Damian: I know, but I don’t have time to look deeper into this right now. Can you provide the page object for which this is failing? It again seems to me to be some kind of metadata problem on the page.

  20. Damian

    Ok, problem solved. Thanks. 🙂

  21. jaya

    All above information is helped me lot.. Created web service and integrated with JD Edwards 2I order system in my organization.

  22. Sergio

    Hey!

    Thank you for the help! It was a perfect start for my project. I need to use some extra functions besides CRUD that Pages provide.

    If anybody needs to use Codeunit Web Services with the Page it is possible!

    First create a Codeunit and publish as an extension of the Page (It has to be published with the same Name, and the functions included need a record parameter of the same type in Page).

    Then few adjustments in Vjeko codeunit (defining the new methods) and voila!!

    Thank you!

  23. massimo

    Hi,

    had you finished to improve your tool for CodeUnit?

    1. Vjeko

      No, not yet, sorry. 🙁

  24. Johannes Wikman

    Thanks Vjeko,

    This is a great tool! It really helped! 😉

    The only thing I’m missing is the possibility to use delegates (not your fault!) to be able to bypass certificate validate in our dev.env. Now we use a custom .NET Class for that.

    Thanks,
    Johannes

    1. Vjeko

      Thanks, Johannes! Unfortunately, yes – you need the custom .NET class for that.

  25. David

    Hi,
    I have some problems when I use 2009 version.
    – I can’t use SETVALUE function with fields that are not Text or Code. When I use the function with a boolean field, for example, I have this error: “The expresion type Microsoft.Dynamics.Nav.Runtime.NavIndirectValue can´t be converted to a value Microsoft.Dynamccs.Nav.Runtime.NavText.”

    – I have a lot of errors like this “CustomerCard does not have a definition for the Territory_Code field”. Where can I find this definitions?

    Thank you!!

    1. Vjeko

      David, can I see the code that causes the error when converting text to indirect value? I haven’t had any, I’ve even used it with the Option field. About the Territory Code field, do you actually have that field on the card, or is it just in the table?

      1. David

        Thank you for your answer!

        This is my code:

        CONNECT(‘192.168.2.125:7099/DynamicsNavXX/WS/XX/Page/CustomerCard’);
        INIT;
        SETVALUE(‘No’,Customer.”No.”);
        SETVALUE(‘Name’,Customer.Name);
        SETVALUE(‘Search_Name’,Customer.”Search Name”);
        SETVALUE(‘Name_2’,Customer.”Name 2″);
        //SETVALUE(‘Our_Account__No_’,Customer.”Our Account No.”);
        //SETVALUE(‘Territory_Code’,Customer.”Territory Code”);
        //SETVALUE(‘Collection_Method’,Customer.”Collection Method”);
        //SETVALUE(‘Blocked’,Customer.Blocked);
        CREATE;

        The commented lines are the lines with error.

        The customer card have this fields in the General group with Visible = FALSE.

        Thanks

        1. Vjeko

          Strange, it works for me on NAV 2013, but I don’t have an instance of 2009 available anymore to test it there. Can you try if you experience the same problem with 2013 as well?

          1. David

            I found the problem. I call the codeunit from a report, and the Language of the report is not ‘ENU’.
            Now It is running!

            Thanks

  26. Dan

    Hi Vjeko

    Great tool! I’m quite new to NAV and It helped a lot. Thank you.

    My question: Is there really no way in the WebService Page to access the values passed with SETVALUE?

    Best regards

    1. Vjeko

      Thanks, Dan! I am not sure, though, what you mean by this question. SETVALUE is used to set the values, not to access the values. Can you please clarify?

      1. Dan

        Hi Vjeko. Thanks for your answer. I try to clarify my problems

        Within my webservice page, I attempt to access the values, that I have set with SETVALUE.
        I have a simple Page that only writes the passed values as a new record into a table. In addition to the insert, i want to call a (cu) function using this values as parameters.

        E.g.:

        Type SubType SourceExpr
        Container ContentArea
        Group Group
        Field “Triggered by Company Name”
        Field “Company Name Called”
        Field “Webservice Called”
        Field “Parameter Type”
        Field Parameter

        OnInsertRecord(BelowxRec : Boolean) : Boolean

        cuItemMgt.SyncItemSCfromWH(“Triggered by Company Name”,”Parameter Type”,Parameter);

        The table insert works fine. No problem.
        But, no matter what I try, the function (SyncItemSCfromWH) always receives blanks or nulls. Even if I call it at the table’s OnInsert Trigger.

  27. Sergio Carbajo

    Hello,

    I’ve been working with Generic Web Service for a while, but never faced this problem.

    I use Transfer Header Card.

    The error shows up on Create method of the codeunit. System.Reflection.RuntimeMoethodInfo.Invoke : Thge max length for a string is 10.

    I’m sending the transfer header no., and there should not be a problem with its length . In nav it is set to code 20…

    Maybe something related to parameters?? any guess?

    1. Sergio Carbajo

      I answer myself… In transfer header insert trigger there’s was code regarding a “user” field which was 10 chaacter lenght.. fixed!

  28. Håkan Svensson

    This was well over my head, but I wonder; Is there a way to make it work also for non-NAV webservices?

    1. Vjeko

      Håkan, yes – it is possible. I might do something like that in the future, but I can’t make any promisses. Principle is the same for all web services.

  29. Sergio

    Thanks for the article Vjeko! Very interesting and useful! Have a nice time in Madrid!

  30. Kim Ørum

    Thanks for the article and code Vjeko – very valuable!

    But it looks like there is a problem with the READ function if you try to do a READ on a page where there is an option value, as one of the key fields.

    For test purpose I made a page with all fields from table 36 – Sales Header and tried this “code”:
    WITH WebService DO BEGIN
    CONNECT(‘http://…../Page/SH’);
    INIT;
    SETVALUE(‘Document_Type’, SH.”Document Type”::Order);
    SETVALUE(‘No’,’1500005′);
    READ;

    And this gives me the error message:
    A call to System.Reflection.RuntimeMethodInfo.Invoke failed with this message: Object of type ‘Document_Type’ cannot be converted to type ‘System.String’.

    It would be appriciated is any had seen/solved this issue.

    Thanks in advance.

    1. Vjeko

      I can’t play with this right now, but I assume you can try with:
      SETVALUE(‘Document_Type’, FORMAT(SH.”Document Type”::Order));

      1. Kim Ørum

        I did try that before my initial post – gives same error result.

      2. Thomas Jensen

        Hi. Any news on this isse that Kim Øvrum describes?

    2. Tihomir

      I’m using this tool a lot lately and there is a workaround for this.
      Instead of using SETVALUE use SETFILTER, so in your example do it like this:
      SETFILTER(‘Document_Type’, FORMAT(SH.”Document Type”::Order));
      SETFILTER(‘No’,’1500005′);

      Instead of using READ use READMULTIPLE but since you only need first record no need to REPEAT – UNTIL block so just add:

      IF READMULTIPLE THEN BEGIN
      END;

  31. Dhan Raj Bansal

    Hi Vjeko,
    Have you upgraded this codeunit for calling XMLPorts/ codeunits etc, as you mentioned in your earlier post that you will do it in future?

    1. taslops

      Maybe someone else is made this code to work with codeunits ? and maybe could share it with us ?

  32. Vidhi

    Hi i had tried to call web service as you guide. i had used your code unit only. But while i am trying to call web service the line

    RequestStream := WebRequest.GetResponse().GetResponseStream();
    is giving me error – “a call to system.Net.HttpwebRequest.GetResponse failed with this message: the remote certificate is invalid according to the validation procedure.”

    I have also passed NAVUserid and password as you suggested that code is –
    ServiceInstance.Credentials := Credential.NetworkCredential(‘Admin’,’password’)
    but still same.

    can you please guide me for above issue.

  33. Starky

    Hi Vjeko,
    I need this CodeUnit for the project that im working right now.

    The site mibuso.com is down because they are working in their new web and its imposible to find this in other site.

    Please, can you upload that CodeUnit in other place and share the link with us, for example in dropbox?

    Thanks in advance.

  34. Elena

    Hi Vjeko,

    I’m wondering the same as some of the other poster’s above:

    Can this be used for web services with SSL?

    I’ve tried but it’s failing for me also.

    Thanks

  35. ssl failing

    SSL not working for me either.

  36. ariunjin

    Dear Vjeko,

    Thank you for your greate tool.

    We are inserting Sales Invoice from one nav database to another using web service.
    The problem is we couldn’t figure out how to read from saleslines?
    There is a GETLINEVALUE function, but not sure how to read repeatedly within salesinvoice multiread.

    Could you please help on this issue?

  37. ariunjin

    Also i tried to create sales invoice updating thought Web Service exactly same way in above example code
    “Creating a purchase order from a sales order”,
    Unfortunately, not working, showing below error:

    THE ERROR IS;

    Microsoft Dynamics NAV
    —————————

    SalesInvoice does not have lines.
    —————————
    OK
    —————————

    If i debug the code, it is stoping in line below on CU Generic Web Service Client

    AssertHasLines()
    IF NOT HASLINES THEN
    ERROR(Text006,Name);

    Need to initiate SalesLine for WS SalesInvoice to SETLINEVALUE? How? Or should i missing something?

    Please, give a guidance for my urgent issue..

    1. Vjeko

      Sorry, I haven’t tested it with sales lines.

  38. Senatord

    Hi, Vjeko, residents and guests!
    Please, tell me. Can I successfully work with this CU under Nav2009R2 Classic client (forms, reports, etc..)? Thank you for attention.

    1. Vjeko

      I am not quite sure of it. It was not developed for 2009 R2, and it may not work correctly. It’s a very very old version of NAV and I hope you understand why I can’t spend time trying to figure out if this would work under it.

  39. ethan0k

    How I can read all row from sales oder?

  40. swicaksana

    thanks a lot Vjeko for the codeunit, it works well in NAV 2015. Is there any new version which support calling OData webservice from another system or another NAV?

    again, thank you very much.

    1. Vjeko

      No, sorry, I never extended it to support this. However, for OData you don’t need anything this complex, it can be as simple as using JSON.NET with HttpWebRequest.

  41. Mohamed Zayed

    Hi Vjeko,
    in regards to your Example “Creating a purchase order from a sales order”
    Is there is a way to Validate a field in the new Created Purchase order using your code?

    This will be really helpful.

    Best regards,
    Mohamed

    1. Vjeko

      What do you mean by “validate”? All fields are always validated when making web service calls.

  42. Mohamed Zayed

    Hi Vjeko,
    Your code is working Perfectly with the English Client! but If I use the German client it will now worl due to an error on this line:
    Object := Enum.Parse(PropertyInfo.PropertyType,ValueText);

    Do you have any idea how can I over come such issue?

    1. Vjeko

      Yes – use the English enum constant names. That’s the only way.

  43. Markus

    Thanks Vjeko for this brilliant piece of NAV-code. We used it to synchronize information between two independent systems and it is working really well (and the code for consuming web services is easy to understand). We’ve had a problem with the memory consumption on the service-tiers, because every CONNECT will compile a new assembly in memory and they will never be released again. So I mixed the function CONNECT with your state-service trick, essentially storing the assembly, the related URI and the WSDL in those static dictionary on the Service Tier and reuse it, when nothing has changed.

    Thanks again.

  44. Duc Nguyen

    Hi Vjeko!
    Can you please write a topic to guide how to create a web service to get list of invoices/vendors and pay invoices in NAV 2009 (using codeunit)?

    1. Vjeko

      Good one 🙂 Honestly?

  45. Javier

    Dear Vjeko,

    I have an error when I tried tu use the CU to update a Purch.Invoice Header through web service.

    This is my piece of code:
    WITH WebService DO BEGIN
    CONNECT(‘https://********/Page/FacturasPendientes’);
    INIT;
    SETVALUE(‘No’,”No.”);
    READ;
    SETVALUE(‘Approve’,FORMAT(“Approve”::Aprobado));
    UPDATE;
    END;

    Is strange because the error is only throwed in the second SETVALUE statment, this is the message:

    Microsoft Dynamics NAV
    —————————

    No se ha creado la instancia de la variable DotNet. Se está intentado llamar a System.Object.GetType en CodeUnit Generic Web Service Client: SetObjectValue
    —————————
    Aceptar
    —————————

    the translation is that the instance of the DotNet variable has not been created when the codeunit is trying to call the method SetObjectValue

    Any idea about that?

    1. Vjeko

      Hm, I think it may have to do with the language. You are trying to assign the constant in Spanish, while .NET layer only sees English. Can you try to put “Approved” instead of “Aprobado”?

  46. Fabian

    Hi my dear partner

    you have some idea about how can i post purchase order? i need to do that from vb.net

    thank you in advance.

    1. Vjeko

      You can’t do it using this example. This is only for page web services, not for codeunit web services. There are plenty of examples how to do what you need around the internet. Sorry that I don’t have much more time to delve into details now… 🙁

  47. Maarten

    I’ve used this codeunit by an conversion/migration from NAV2009 to NAV20016. In NAV2009 i’ve publised the data as webservice.
    Simple example of the code in NAV2016:

    ConvertSalesPerson()
    TimeVar[1] := TIME;
    Window.OPEN(Text001);
    WITH lWebService DO BEGIN
    CONNECT(‘http://dev02:7047/DynamicsNAV/WS/CompanyName/Page/SalesPersonWS’);
    Window.UPDATE(1,Salesperson.TABLECAPTION);
    Salesperson.DELETEALL(TRUE);
    SETFILTER(‘Job_Title’, ‘@inactief’);
    SETFILTER(‘Name’, ‘*@NIET GEBRUIKEN*’);
    IF READMULTIPLE THEN
    REPEAT
    CLEAR(Salesperson);
    UpdateWindow(2,Salesperson.Code);
    IF NOT Salesperson.GET(GETVALUE(‘Code’)) THEN BEGIN
    Salesperson.Code := GETVALUE(‘Code’);
    Salesperson.INSERT(TRUE);
    END;
    Salesperson.VALIDATE(Name, GETVALUE(‘Name’));
    Salesperson.VALIDATE(“Job Title”, GETVALUE(‘Job_Title’));
    Salesperson.MODIFY(TRUE);
    UNTIL NEXT = 0;
    END;
    Window.CLOSE;
    TimeVar[2] := TIME;
    LogDuration(‘Salesperson’,TimeVar[1],TimeVar[2]);

    It’s a nice and fast way to convert the data!

    1. Vjeko

      Thanks for sharing 🙂

      1. isil

        Do you have any example code with GETLINEVALUE function

  48. Sergio

    Thx!!!! This save me 🙂

    1. Vjeko

      You’re welcome! I am amazed that this is still pretty much alive out there 🙂

  49. Antonio

    Hi Vjeko,
    I try to use your codeunit to synchronize the item table of two company (on different server). But I get error with read-only field i.e. Last Date Modified. It is possible to know if a field is read only in Web Services, in this case for Item Card page?

    1. Antonio

      I try to use an table for exclusion fields (read-only fields), but I get another error when I modify the unit price: the error say that: Field CalcUnitPriceExclVAT is readonly! But CalcUnitPriceExclVAT is a global function on the Item table … Why I get this error?

      1. Vjeko

        Because the page field you are trying to modify is apparently bound to a function. Rule is – if you can’t change it from UI, you can’t change it from Web Services.

    2. Vjeko

      It’s not possible directly. You’d have to somehow access page metadata (it’s an XML document in the Object Metadata table) and read it from there. And perhaps also do this for the underlying table. It’s not trivial.

  50. guidorobben

    I have a problem with date fields? When I get the date from the GETVALUE function, the date is in the dutch format instead of english format. AND it is the date minus one day. How does this happen?

    1. ThJens

      I have the same problem with dates as well. I need to send data from one DB in one language, to another DB (on another server) with different language and timezone. Maybe something to do with that?
      In any case, I ended up splitting the date into 3 integers, and combining them to the correct date later.

      1. guidorobben

        I changed the field to text and filled it with the Format(,9) option so it becomes a xml date value.

    2. Vjeko

      Sorry, I don’t know this (anymore). There must be ways to do this, but I am not actively maintaining this codeunit anymore, so I can’t help you directly.

  51. Scott

    Vjeko Fantastic! With a little work I have managed to complete support for SubPages. I had to change ‘Lines’ from Array to Collection and assign object to Entity.Lines when move through records with Entitys.NEXT. Also added a function LINES_NEXT to move though collection of Lines.

    Works great! Good to see you at NAV Tech Days 2017! Keep up the good work! Thank you!

    1. Vjeko

      You’re welcome! I am always happy to hear that my work is useful to others.

    2. guido robben

      Can you send your code? Maybe Vjeko can update the post?

  52. Francesco

    Sometimes I have an error when I tried tu use the CU to update a custom table through web service.

    This is my piece of code:

    WITH WebService DO BEGIN
    CONNECT(**********************************************’);
    INIT;
    SETVALUE(‘Id’,VoucherD.Id);
    READ;
    SETVALUE(‘UsedQuantity’,VoucherD.UsedQuantity);
    UPDATE;
    END;

    And this is the error:

    Calling to System.Reflection.RuntimeMethodInfo.Invoke failed with this message: Other user has modified “Voucher_Line_detail” “Id=CONST(6575)”

    Thanks

    1. Vjeko

      Well, I can imagine people are getting errors with this, but this was written for NAV 2009 R2, and I never really updated it for anything newer. I can’t provide any active support for this, sorry 🙁

  53. hemant sharma

    Hello Sir,
    i am getting this error
    CustmerList does not have a definition for the field.

    1. Vjeko

      Yes, very likely. This is mostly proof of concept and not a finalized solution. Also, it was intended to be used on NAV 2009 R2, and was never updated for any future releases – I would be surprised if it just worked without any changes.

  54. Thomas Jensen

    Hi. I hope if some of you subscribes to this can answer. This has worked like a charm for over a year now, But now I get “A call to System.Net.HttpWebRequest.GetResponse failed with this message: An existing connection was forcibly closed by the remote host”
    This only happens if there are a sizeable (well, not very much) amount of data involved.
    A google search reveals that one copuld try to set keepAlive := false, but i ‘cant see a class that have this property.

    Any pointers would be helpful.
    Thanks.

  55. JJ

    This is a great post that helps me a lot! i am using this to handle some intercompany stuff. However, has anyone made it work for codeunit? I use the Web Service extension method where i create a codeunit webservice entry with the same name as the Page Web Service and just not publish it. in the WSDL of the page WS, i do see the DoSomething function from the codeunit in the WSDL, but i failed to make it work, i am getting some .Net Runtime error when i called the DoSomething function.
    “A call to System.Reflection.RuntimeMethodInfo.Invoke failed with this message: Object of Type XXX cannot be converted to System.String’

    I made a copy of the UPDATE function , perhaps it is something in here that i did wrong….any ideas?

    DoSomething()
    AssertAllowed(DOSOMETHINGALLOWED);
    AssertInitialized;

    Parameters := Parameters.CreateInstance(GETDOTNETTYPE(Object),_Create.GetParameters().Length);
    Parameters.SetValue(Entity,Parameters.Length – 1);

    Service := Activator.CreateInstance(ServiceType);
    Authenticate(Service);

    _doSomething.Invoke(Service,Parameters);
    Entity := Parameters.GetValue(Parameters.Length – 1);

  56. Cuthbert

    I’m facing this error when trying to update Nav with a payload from webservice. How can i fix this:
    SOAP ERROR: /var/www/Company/production/Company_ws/chr/components/AssetVerificationUpdate.inc.php on line 159. REASON: Other user has modified “OTI_Asset_Varification” “No.=CONST(XXXXXX)”

    1. Vjeko

      You can’t. If another user has modified a record in between you reading and writing, this is what you get. It’s called concurrency. You’d need to catch this specific error, and if it occurrs, do the re-read, and then attempt re-write.

  57. callmevandie

    Hi Vjeko,

    nice post, i applied your codeunit in my testing db, but unfortunately the system will show the error if the company name with comma inside.

    here below the error :

    Microsoft Dynamics NAV

    A call to System.Reflection.RuntimeMethodInfo.Invoke failed with this message: Service “Tester%2C Company/Page/Customer_List_Tester” was not found!

    OK

    and the system pointing to that codeunit function CREATE :
    _Create.Invoke(Service,Parameters);

    can you help me how to configure it? thanks.

    1. Vjeko

      Sorry, I can’t do much to help you with this. Change the name of the test company if the comma in the name is the problem.

  58. MAL

    Hi Vjeko,

    This is some great stuff thanks for this!

    Hope someone tried this with codeunit instead of page.

    Thank you & God bless!

  59. Alice Jackson

    Great post (as always)… I’m just curious. What search terms did you use to discover those (creative commons licensed) photos? That first one is so so perfect for this topic.

    1. Vjeko

      Seriously, you are asking me about what search terms I used to discover a photo I put there ten years ago? Honestly, I don’t remember.

      However, the “(creative commons licensed)” part of your comment sounds a bit sarcastic to me, so what is it really that you are asking me about?

  60. Johnson Pv

    Hi Vjeko,

    I am facing below error, A call to System.Net.HttpWebRequest.GetResponse failed with this message: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.

    Thanks,
    johnson

    1. Vjeko

      Sorry, don’t know what’s causing this. Firewall, network configuration, something of the sort. It’s not my code, and it’s not BC/NAV, at least that’s obvious from your description of the problem.

  61. José María Bravo (from Spain)

    Thank you very very much Vjeko. It works fine with BC14, the last C/AL edition.
    I only have one problem making READ with Option fields in primary key of the table. But there are several ways to do the same things. 🙂

    1. Vjeko

      You’re welcome, and I am glad this (very, very) old piece of code I did still helps people. I imagine a lot will not work anymore, because 10+ years have passed. Thanks for the comment 😊

  62. Meriam Bambia

    Hello,

    Here is my code:

    1 WITH WebService DO BEGIN

    2 CONNECT(‘http://10.150.1.109:7057/ENTW/WS/K-Solutions GmbH/Page/ServiceContractHeader’);
    3 //Service Contract header
    4 INIT;
    5 SETVALUE(‘Contract_Type’,1);
    6 SETVALUE(‘Customer_No’, ‘123’);
    7 SETVALUE(‘Description’, ‘TestContract’);

    8 //Sevice ContractLine
    9 NEWLINE;
    10 SETLINEVALUE(‘Description’, ‘TestContractLine’);

    11 CREATE;

    12 END;

    If I comment the lines 9 and 10, a service contract header is created. Howver, with the whole code I get this error (in CREATE level):

    This message is intended for C/AL programmers: Error when calling ‘System.Reflection.RuntimeMethodInfo.Invoke’: ‘Description’ must contain a value in ‘Service Contract Line’: ‘ContractType=Contract, ContractNo.=123, LineNo.=10000’. The value must not be zero or empty.

    Why do I get this error even though I set the value of Description field in SETLINEVALUE(‘Description’, ‘TestContractLine’); ?

    1. Vjeko

      I don’t honestly know. I’d suggest you try debugging on your end to see what’s causing this behavior.

Leave a Reply