NAV Web Services – Pages vs. XMLports
There are two major methods for publishing complex NAV functionality as a web service: publishing a Page object, and publishing a Codeunit object with a function that uses an XMLport as a parameter. Which one should you use?
Like Obi-Wan Kenobi and Captain America here, Pages and XMLports are both awesome, but they should be used for different jobs. Whether you use a published Page or an XMLport depends on the requirements of your project. I’m going to outline the pros and cons of each approach, and hopefully that will guide you towards making the decision that fits your requirements.
One of the great things about publishing a Page object is that it makes filtering really easy. Fields are available for filtering just like they would be for a human NAV user.
When you’re using an XMLport, however, filtering is trickier—you have to add code for the filters that people consuming your web service will need. If you’re going to be giving consumers multiple filtering options, I’d actually recommend building an XMLport just for filtering that writes to a temp table or a large array, rather than making the filters parameters of your service. (Remember, you can have multiple XMLports as parameters in a Codeunit function!) You’ll have to communicate the available filter fields to your web service consumers instead of having them be self-evident in the descriptions, but using this method gives you the ability to add new filters later without having to change the service definition.
Sometimes, however, we need to filter a recordset that isn’t a matter of just looking at a range of values in a particular set of fields. Sometimes we need to do a filter like “give me all the sales orders with an item that came from Bolivia”, and there is nothing in our sales line or sales header table to indicate the country of origin for items. In this case, where we need to look at table A to determine which records from table B need exporting, the XMLport is probably the way to go.
When you are dealing with a published Page, you can use the setSize parameter of the ReadMultiple function to tell NAV how many records to return; this is useful when you’ve got a service that could be returning a very large recordset and you need to consider network latency.
XMLports, however, will not give you the option to limit the number of records returned out of the box; you’ll need to implement all of that yourself if you need it to be there. I’ve done this and it’s not too difficult; I just wound up putting a subset of my intended records in a temp table—but it’s still something that takes up development time, and so it’s something to consider when choosing between Pages and XMLports.
Functionality and User Interactivity
If you are going to publish a Page as a web service, and the Page is also used by human NAV users, you need to consider the differences between how the people interact with the Page compared to how the web service consumers will interact with the Page.
This is more complicated than just making sure that all your CONFIRM and MESSAGE dialog boxes are wrapped in GUIALLOWED checks; web service consumers and human users can need different function sets and different sets of data in order to meet their needs. Consider making separate versions of your Page object for people and for web service consumers, tailored appropriately to your intended audience. Some people say that you should always make a separate copy of the Page for publishing as a web service, but I don’t know if it’s worth the effort and added maintenance for simple Pages. (For Pages that require complex interactions, like documents, it’s definitely a good idea.)
XMLports don’t have this issue, because humans don’t use them.
If you’ve tried consuming the Sales Order Page as a web service, you probably started off jumping right in, writing code to set all the necessary values on the object, and then calling the Update function on the service to write it to the database. And then you ran your code, and NAV gave you a bunch of errors, or you went to look at your results and several of the field values you’d set in code weren’t in the database at all.
After some struggles, you figured out that you needed to start out with calling the Create function, and then you had to set some fields, call the Read function to get the updated record, set some more fields, call the Read function again, etc., etc., until you were done with your record. The trial and error of all of that was a hassle.
The challenge of consuming Pages is that NAV is running all of the OnValidate triggers for the fields you write, and that logic can cause some screw-ups that require several calls to the Page.Update function in your consuming code. As far as I know, there is no way to specify which order the fields on a Page are written in, so you have to do a lot of experimentation in your service consuming code to make sure that your database write actually worked as intended. This was a huge challenge in the original release of NAV 2009; the implementation of published Pages was greatly improved with subsequent releases, but it can still be a thorny development problem in NAV 2013.
The great thing about XMLports is that they don’t necessarily have this problem. You can put together an XMLport that stores data in a temp table or a set of variables and then you as a developer can choose which fields are written when, so that your web service consumers don’t have to do all of that trial and error.
The other great thing about XMLports is that you get the chance to examine the data before you write it to the database, so if you’re building a system that could have dirty data, you can clean it up before you insert it into your database by adding formatting or truncating strings or whatever was required. You could also use an XMLport to design a system that needed to be particularly fault-tolerant by just skipping the writes for fields with bad data and then returning an array of values (or something else) letting the consuming service know which fields need to be corrected.
The downside of this is that it works because XMLports publish just about every field to a web service consumer as a string instead of the actual database type, so you may have to sanitize the data while you’re writing it. Pages don’t have this issue; fields in pages show up as their appropriate types, including enumeration values for Option fields. Then again, you might want to sanitize that data that you’re getting from a web service consumer—so think carefully on this point.
As you can see, there isn’t a checklist of points you can go through to determine when to publish a Page and when to publish an XMLport. Think carefully about what you and your web service consumers are going to do with your published functionality before deciding to go one direction or the other.
Feel free to comment if you’ve got some hard-earned wisdom about making this decision!