NAV 2009 Web Services: Extending a page web service

Are you familiar with Freddy's blog? As I said in my previous post (and in my presentation about Web Services), Freddy's blog is the "Mekka" of Web Services. And I should have known ... after finishing this blog, I was browsing through his one, and found quite exact the same blog as I wrote here Sad. Stupid me. Here you can find Freddy's entry. But I did the effort, so I publish it anyway. The solution is quite the same, but still a little bit different Smile, so may be it's useful for you.

This application is something I always use in my demo's. It's nice to see how easy it is to publish and use a page-based web service. It's even nicer to see that you can use that same web service to do more. I use the "Sales Invoice"-page (page 43). Publishing it, is nothing more then inserting a record in form 810 "Web Services", and placing the checkmark.

As you can see, I call my service "WS_Salesinvoice". The name is important to extend it later on.

As you know, you can see your services here: http://localhost:7047/DynamicsNAV/WS/Services, supposing you've published it on your local machine. To be able to use your web service, you have to enter a company as well, so the URL would be looking something like:

http://localhost:7047/DynamicsNAV/WS/COMPANYNAME/Page/WS_SalesInvoice

Anyway, let's try to use it. For the first time in the history of Waldo's Blog, I will be trying to explain a VS.Net application ... which I don't really feel very familiar with anymore .. so don't be to critical about the code... (pppplease, Roger Rabbit would say Smile).

Open Visual Studio and start a new Windows Forms Application. I will show my code in C#, so it might be cool you would do that as well. I called my project "PostSalesInvoice":

First, i want to make a connection to my web service. You can do that by right click on "References" in the Solution Explorer, and select "Add Service Reference". Then "Advanced" and "Web Reference", and then you find a box where you can paste your the URL like above. You will get the list of methods of your page-based web service:

Notice I called my Web Reference name: "SalesInvoice". After that, click "Add Reference". Then, I create the following form by dragging a datagrid and two buttons on the form:

You can clearly see what I'm trying to do: list the invoices (get data from my page-based-web service) and post a selected invoice (extend my page-based web service with the possibility to post the selected invoice).

Now, how do I fill that datagrid? First of all, I create a function "LoadDataGrid".

private void LoadDataGrid()

{

// Initialize the Service

//localhost.Customer_Service service = new Customer_Service();

//service.UseDefaultCredentials = true;

   

SalesInvoice.WS_SalesInvoice_Service MySalesInvoicesService = new SalesInvoice.WS_SalesInvoice_Service();

//MySalesInvoicesService.UseDefaultCredentials = true;

   

//Read Records

SalesInvoice.WS_SalesInvoice[] Invoices = MySalesInvoicesService.ReadMultiple(null, null, 0);

   

//Fill Grid

dataGridView1.DataSource = Invoices;

}

You can copy/post the code above and put it in your project (just put it in the Form-class. After that, double click on the button "List My Sales Invoice" and call that function:

private void button4_Click(object sender, EventArgs e)

{

LoadDataGrid();

}

If you run the application, you get an overview of invoices in your grid:

You see, all columns, including the Key-column. To hide this column, you could add this line of code in the LoadDataGrid-function:

//Hide columns
dataGridView1.Columns[0].Visible = false; //Key Column

Next phase: post the selected invoice. I don't have a method in my web service to post my invoice, so this is where we are going to extend the web service with this possibility. Very simple! I just created a codeunit with a function. In this function, the signature is important: the first parameter should be the same record variable of the page you published (in our case, "Sales Header"). This is my (only) function of my codeunit:

PostInvoice(precSalesinvoice : Record "Sales Header")
CODEUNIT.RUN(CODEUNIT::"Sales-Post", precSalesinvoice);

Indeed, only one line of code.

What's following now, is the magic Wink. We are not going to publish the codeunit as a web service, but we are going to extend the existing web service (WS_SalesInvoice) with the function in the codeunit (I couldn't find a more complicated way to say this...). You can do this by inserting a second record in the Web Services form:

Important: use exactly the same Service Name!

Notice: it's not necessary to publish this codeunit as a web service. I don't want a separate web service with this codeunit, I only want to extend the existing page-based web service.

That's all!!! There is nothing more to it.

But let's check AND use this new method. First, in my Visual Studio project, I have to update my web reference to make my new method available in my VS project: right click on the Web Reference and click "update Web Reference". But to show you clearly, let's just delete the "SalesInvoice"-web reference, and add a new one with the same URL. You'll see the PostInvoice method was added:

Cool. So let's use it now (make sure you call your web reference name "SalesInvoice" again). Double click on the "Post" button, and copy/paste this code:

   

SalesInvoice.WS_SalesInvoice_Service MySalesInvoicesService = new SalesInvoice.WS_SalesInvoice_Service();

MySalesInvoicesService.UseDefaultCredentials = true;

   

String MyString = "";

   

//**** GET THE SELECTED RECORD

try

{

DataGridViewRow MyRow = dataGridView1.SelectedRows[0];

MyString = MyRow.Cells["No"].Value.ToString();

}

catch

{

System.Windows.Forms.MessageBox.Show("Not succeeded. Are you sure you REALLY selected a record ;°) ");

}

   

//*** POST THE INVOICE

if (MyString != "")

{

Boolean success = true;

   

SalesInvoice.WS_SalesInvoice MySalesInvoice = new SalesInvoice.WS_SalesInvoice();

MySalesInvoice = MySalesInvoicesService.Read(MyString);

   

try

{

MySalesInvoicesService.PostInvoice(MySalesInvoice.Key);

}

catch (Exception MyE)

{

success = false;

System.Windows.Forms.MessageBox.Show(MyE.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);

}

   

if (success)

{

LoadDataGrid();

System.Windows.Forms.MessageBox.Show("Invoice " + MySalesInvoice.No + " Posted successfully");

}

}

The code is quite self-explanatory, isn't it:

  1. Get the selected record (I need that Key)
  2. Call the function
  3. Trap any error and show it (any error in NAV will be shown in .NET).

On side remark: it's important that you SELECT the record by making it completely blue. It's the only way that I found to post a certain record. Selecting one cell is not enough...

Conclusion

The conclusion is that I can a page for data and codeunit for additional business logic ... with one web service (and not two) as a result.

Again, probably the C# code is probably not the most nicely written peace of C# you've ever seen, but try to look through that. I'm no Freddy ;°)

For your convenience, you can download the codeunit and VS project here.

Comment List
  • Have you used an editable page?

  • hello;

    i m not able to find the create method in the my page. so can update or insert the data from web page to NAV page.

    please give me the solution as soon as possible.

    thanks in adv.

  • hi,Good article and more useful. Thanks for posting, Keep going.....

  • Thanks a lot Waldo.

    You were right. I rebuilt Codeunit 6810 and after I had the same error for another Codeunit.

    Finally, works fine!

  • @JAJ & @sgregorio

    I suggest you log a thread on mibuso.  more people will be able to respond.  For me it's guessing what your problem is :-(

  • Hi.  Thanks for the code.  I have a problem, I don't get any error, though I don't get any data either.  The dataGridView creates all the columns but shows no rows, so it appears it's getting at least the structure of the table.

    I've confirmed that the server is using the correct database and company.  I've tried the Walktrough in msdn.microsoft.com/.../dd338962.aspx and it works fine (in the same machine and database). I've tried to make a service using a codeunit instead of a page, and it works fine too.  I've tried to make the same example with that WebService (the one in the example, page Customers Card) and it works fine too (it populates the dataGridView with customer data).

    I'm just curious why it doesn´t work with Sales invoices.  May it be permissions? Or what should it be?

  • Yes I have, but I have the same problem.

    My version of NAV is W1 6.0 R2(6.00.32465).

    Maybe there is same hotfix about it. I am going to get a hotfix.

    But I wonder if the correct work of it is that return the NAV error.

    Thanks for you attention.

  • Well .. it says that the metadata of your codeunit (6810) is not that good.  Have you tried to rebuild it?

  • Hi Waldo,

    I have a doubt about the error handler in Web Service. If I use this example and I try to post a invoice that have some error, I recived the error below :

    "Metadata for object of type CodeUnit with id 6810 is in a failed state. This is caused by a previous exception: The NAV System has changed while you were performing your activity. Please close your current task and try again. If you are unable to complete the activity, please contact your System Administrator. Information for developers: Another user has modified CodeUnit 6810. Because the underlying data does not exist or is a different type, the object cannot be compiled correctly until the problem is fixed. Error details: c:\Documents and Settings\All Users\Application Data\Microsoft\Microsoft Dynamics NAV\60\Server\MicrosoftDynamicsNavServer\source\Codeunit\Codeunit6810.cs(662,43) : error CS1501: No overload for method 'ToNavAutomation' takes '1' arguments"

    You say that trap any error and show it (any error in NAV will be shown in .NET).

    Do you Know which is the problem?

    Is Web Service NAV be able to respond wiht the NAV error?

  • @FJPerez Check your app.config/web.config and see if the URL details are correct for the services. I had this issue and for some reason this string was inside of the app.config file.

  • seems you have unsupported stuff in your codeunit or page.. .

    i suggest you post the complete solution on mibuso to get help.  you can send me a pm on mibuso to point my attention to it, if you want..

  • Respected Sir;

    I'm very new in this stuff, I mean C/SIDE, C/AL in Dynamcis NAV as well. I'm using NAV 2009 R2.

    As you guided, I tried my best; but I'm getting a error.

    <?xml version="1.0"?>

    -<s:Envelope xmlns:s="schemas.xmlsoap.org/.../">-<s:Body>-<s:Fault><faultcode xmlns:a="urn:microsoft-dynamics-schemas/error">a:Microsoft.Dynamics.Nav.Service.WebServices.ServiceBrokerException</faultcode><faultstring xml:lang="hi-IN">Service "CRONUS India Ltd/services/Page/SalesInvoice" was not found!</faultstring>-<detail><string xmlns="schemas.microsoft.com/.../">Service "CRONUS India Ltd/services/Page/SalesInvoice" was not found!</string></detail></s:Fault></s:Body></s:Envelope>

    Please do reply on this...

    Sir I may not visit this website, when you repost;

    but please write your wise word in my mail address:

    mrinal@samadhanindia.com.

    or www.facebook.com/MrinMaX

    Sir please I need your assistance !!!

  • Cheers Waldo,

    This post has helped fill in some gaps that i have spent many hours trying to fill, and above all in an easy-to-understand manner.

Related
Recommended