The following sections provide suggestions and describe issues to be aware of as you develop Web service clients for Microsoft Dynamics NAV 2009.
Returning Data from Codeunit Web Services Using XMLports
Returning an XMLport from a Web service allows you to design schemas and to support multiple complex types on a single method call. For example, you can use an XMLport if you need to get a bookmark back as you work with a Page Web service.
See this blog post for a demonstration of this technique.
Using Specified Properties with Visual Studio to Indicate the Presence of a Value in a Field
When you set a field to a value in the code for a Web service client and then send the value back to the Web service, such as when using the Create or Update operation, the field value is not actually updated to anything but its default value. This issue can occur if you are using proxies that are generated by Visual Studio or the tools in the .NET Framework SDK.
This happens because of how autogenerated proxies and the .NET Framework handle values in XML documents that are exchanged between the Web service and the client. The issue is not specific to Microsoft Dynamics NAV.
Consider the schema for the following two fields on this Customer Card Web service:
Copy Code | |
---|---|
<xsd:element minOccurs="0" maxOccurs="1" name="Credit_Limit_LCY" type="xsd:decimal" /> <xsd:element minOccurs="0" maxOccurs="1" name="Salesperson_Code" type="xsd:string" /> |
Both fields are optional, which means that they may or may not be present in the XML document. One field is a decimal type, and the other field is a string because it is declared as a Text data type in Microsoft Dynamics NAV.
If both values are present, then the XML document should contain the following lines:
Copy Code | |
---|---|
<Credit_Limit_LCY>1000</Credit_Limit_LCY> <Salesperson_Code>JR</Salesperson_Code> |
But if there is no information about the credit limit, then the document should contain the following line:
Copy Code | |
---|---|
<Salesperson_Code>JR</Salesperson_Code> |
If the credit limit is zero, then the document should contain the following line:
Copy Code | |
---|---|
<Credit_Limit_LCY>0</Credit_Limit_LCY> |
For the decimal type and all .NET value types, this "present-or-not" state can be controlled in the proxy objects with a Boolean *Specified property:
Copy Code | |
---|---|
if (salesOrder.Credit_Limit_LCYSpecified) there is a value present in salesOrder.Credit_Limit_LCY else there is no useful value in salesOrder.Credit_Limit_LCY |
Consequently, if you assign a value in the value type, then you
should also define it as present by setting the accompanying
Boolean *Specified property to true
:
Copy Code | |
---|---|
salesOrder.Credit_Limit_LCY = 1000; salesOrder.Credit_Limit_LCYSpecified = true; |
To specify that there is no useful value in the value type
salesOrder.Credit_Limit_LCY
, set the accompanying
Boolean *Specified property to false
:
Copy Code | |
---|---|
salesOrder.Credit_Limit_LCYSpecified = false; |
The accompanying value in
salesOrder.Credit_Limit_LCY
will now be
disregarded.
.NET reference types, such as the String class, are handled differently because .NET declarations that are based on those types can be null, which means that they can have an explicit expression of no value present:
Copy Code | |
---|---|
if (salesOrder.Salesperson_Code != null) there is a value present in salesOrder.Salesperson_Code else there is no value in salesOrder.Salesperson_Code |
If you assign a value, then you implicitly also define it as present:
Copy Code | |
---|---|
salesOrder.Salesperson_Code = "JR"; |
To specify that there is no useful value in
salesOrder.Salesperson_Code
, set it to null:
Copy Code | |
---|---|
salesOrder.Salesperson_Code = null; |
Example
Copy Code | |
---|---|
SalesOrder salesOrder = new SalesOrder(); salesOrder.Order_Date = DateTime.Today; salesOrder.Order_DateSpecified = true; salesOrder.Currency_Code = "SEK"; salesOrderService.Create(ref salesOrder); |
Preserving Data When Working With a Statically Generated Proxy
You can lose data if you develop a Web service client that interacts with a statically generated proxy. We recommend that you implement a process to prevent this from happening. For example, you can generate your proxy as a part of your automated build of the client.
You can run form 810, Web Services, from the Classic client and publish page 21, Customer Card, as a Web service with Customer as the Service Name value. You can then add a Web reference to this service from a C# console application and insert the following code in the Main method:
C# | Copy Code |
---|---|
static void Main(string[] args) { CustomerService.Customer_Service svc = new CustomerService.Customer_Service(); svc.UseDefaultCredentials = true; Customer c = svc.Read("01121212"); Console.WriteLine(c.Name); Console.ReadKey(); } |
When you run the application, you will see the following output:
Copy Code | |
---|---|
Spotsmeyer's Furnishings |
You can then go back to page 21 and set the Name property for the control that is bound to the Name field to CustomerName, and save the page.
Finally, you switch back to the console application without updating the Web reference and run the code. Instead of getting an error message that indicates that the Web request does not match the Web service description, you do not get an error message, and Console.WriteLine shows an empty line.
Similarly, a client Web service cannot detect if a field has been removed from a page since a proxy was last generated.