Open Data Protocol (OData) is a data access protocol initially defined by Microsoft. In NAV 2013 Microsoft first added a support for OData. On the Developer Network Microsoft has a few walk-throughs aimed to get us started in using both SOAP and OData web services.
To get started with OData first make sure that the OData service is enabled on your developement server.
As you can see on the image above I also enable the use of NTLM Authentication. In a production environment OData should use SSL as described in this walk-through from Microsoft.
I want to share with you a few points that I have found out and are not obvious in the walk-throughs.
When an external application makes a OData request NAV will behave the same way as a Windows Client would do. The server will do the login routine by executing trigger 1 in Codeunit 1, CompanyOpen and when the request is finishing the server executes the CompanyClose trigger. If the request if for a Page object then all the page triggers are executed, OnInit, OnOpenPage and so on.
The OData will only show the fields added to the Page or to the Query with the table primary key fields added. Lets take a closer look at how the Page object works with OData.
In the OnOpenPage trigger and in the SourceTableView property it is possible to add filters. These filters will apply to the OData stream and you will not be able to insert data into NAV outside of these filters – same functionality as if you where using the Page in the Windows Client. The properties; Editable, InsertAllowed, ModifyAllowed and DeleteAllowed all work with OData. Lets for example look at Page 39 – General Journal. In the OnOpenPage trigger the code is filtering the table data with a Template Name and a Batch Name.
From OData, the variable OpenedFromBatch will always be False so the first template and batch for the PAGE::”General Journal” will always be selected and new entries will always be inserted into that journal. This also means that it is not possible to use Page 39 to read the journal lines from any other journal then the first one. Fields that are not visible in a Page are visible and usable in OData.
When creating a new record the code in the OnNewRecord trigger is executed.
This will all work fine for the first template and batch. The AutoSplitKey property is also active so as long as you are fine with inserting in to the default journal then you can use this Page for your OData web service.
The easiest way is still to create a new page dedicated to the web service functionality, show the primary key fields in the page and skip the OnOpenPage and the OnNewRecord code. I use the OnNewRecord code to put in default values for the table I am inserting into.
On the Microsoft web site walk-through it is shown how to create a new customer, look for a customer and modify a customer.
I have found that I want to add one line to that example
NAV nav = new NAV(new Uri("http://localhost:7048/DynamicsNAV/OData/Company('CRONUS%20International%20Ltd.')"));
nav.Credentials = CredentialCache.DefaultNetworkCredentials;
nav.IgnoreResourceNotFoundException = true;
Without IgnoreResourceNotFoundException the following code example will return an exception if the customer is not found within the given filter.
private static Customer GetCustomer(NAV nav, string customerNo)
var customers = (from c in nav.Customer
where c.No == customerNo
foreach (Customer customer in customers)
By combining a Get function like this with a New or Modify function it is easy to update the existing value for any given table in the database.
private static Boolean AddNewDefaultDimensionCodeValue(NAV nav, int tableNo, string no, string dimensionCode, string dimensionCodeValue)
DefaultDimensions existingDefaultDimension = GetDefaultDimension(nav, tableNo, no, dimensionCode);
if (existingDefaultDimension == null)
DefaultDimensions newDefaultDimension = new DefaultDimensions();
newDefaultDimension.Table_ID = tableNo;
newDefaultDimension.No = no;
newDefaultDimension.Dimension_Code = dimensionCode;
newDefaultDimension.Dimension_Value_Code = dimensionCodeValue;
existingDefaultDimension.Dimension_Value_Code = dimensionCodeValue;
private static DefaultDimensions GetDefaultDimension(NAV nav, int tableNo, string no, string dimensionCode)
var dimensionValues = (from d in nav.DefaultDimensions
where d.Table_ID == tableNo && d.No == no && d.Dimension_Code == dimensionCode
foreach (DefaultDimensions dimensionValue in dimensionValues)
Remember, that without the SaveChanges nothing will be updated in NAV.
Now go ahead and use OData to integrate NAV with all your external systems and devices. Good luck.