Using the FoxPro Proxy to access Arrays

In the last topic you saw how to interoperate with the basic service and simple objects. Now let's look at a few examples that deal with downloading a number of items and then updating items which are represented as arrays in .NET.

Arrays are problematic in COM Interop generally, because FoxPro's Array format doesn't map cleanly to .NET arrays. For this reason wwDotnetBridge provides a ComArray class that wraps .NET arrays and simplifies access and manipulation of those arrays from FoxPro.

Reading Array Results

First lets download a few inventory items from the service:

*** Download an array of items - returned as a ComArray instance
loItems = loService.DownloadInventoryItems("")

? "A few items from the Store:"
FOR lnX = 0 TO loItems.Count - 1
    loItem = loItems.Item(lnX)
   ? loItem.Sku + "   " + loItem.Descript + ;
     "  " + TRANSFORM(loItem.Price,"@99,999.99")
ENDFOR

Reading array results is super easy. The Proxy automatically returns array results as ComArray instances.

The ComArray that comes back has a .Count property and an .Item() method that can be used to retrieve individual items. Note that the ComArray is 0 based, so the first index is 0 not 1 which is reflected in the FOR loop!

ComArray also includes AddItem, RemoveItem, Clear and a host of other helper methods to manipulate the array. It's an easy way to manipulate a .NET array from FoxPro without actually turning it into a relatively useless FoxPro array.

Updating an Array

Next, lets retrieve items from the service and then update the array and send it back to the server:

loItems = loService.DownloadInventoryItems("")

? loItems.Count  && 10

*** Create and add 2 new items
loItem = loItems.CreateItem()  
loItem.Sku = "NewItem"
loItem.Descript = "New Item Description"
loItem.Price = 100.00
loItems.AddItem(loItem)

loItem = loItems.CreateItem()
loItem.Sku = "NewItem2"
loItem.Descript = "Second New Item Description"
loItem.Price = 100.00
loItems.AddItem(loItem)

? loItems.Count  && 12

lnUploadCount = loService.UploadInventoryItems(loItems)

The DownloadInventoryItems() method retrieves an array and turns into an internal structure called a ComArray which abstracts a .NET array so it's easy to use from FoxPro.

DownloadItems returns the array as before, but in the code above we create two new items to add to the existing array. The key method here is:

loItem = loItems.CreateItem()

which creates a new element. CreateItem is a shortcut method that knows what type the type of the array items and creates a new instance of that type. Essentially CreateItem() is a shortcut for the following code:

loItem = loService.oBridge.CreateInstance("WebStoreService.wws_itemsRow")

that creates a new strongly typed .NET object instance. Each new item created is then added to the array via the AddItem() method.

Passing an updated or new Array back to the Service

Finally the array is passed to the method that expects an array input. The signature of the .NET function is:

public int UploadInventoryItems(WebStoreService.wws_itemsRow[] items)

In order to pass an array to .NET you have to use the ComArray structure. So from the code above we can use:

*** loItems is a ComArray from the code above
loService.UploadInventoryItems(loItems)

behind the scenes the Proxy class makes a call to wwDotnetBridge InvokeMethod, which knows how to convert the ComArray you pass into a native .NET array that matches the actual .NET proxy method parameter.

The key to understand here is that .NET arrays don't work in FoxPro directly if you need to modify them so whenever you return an array wwDotnetBridge returns you a ComArray. Whenever you pass an array you have to use wwDotnetBridge.InvokeMethod

Creating a new Array

Again remember that you can't pass FoxPro arrays to .NET so you need to create a new ComArray populated with .NET items. To do this:

// Create an array instance of the .NET type
loItems = loService.oBridge.CreateArray("WebStoreService.wws_itemsRow")

? loItems.Count  && 10

*** Create and add 2 new items
loItem = loItems.CreateItem()  
loItem.Sku = "NewItem"
loItem.Descript = "New Item Description"
loItem.Price = 100.00
loItems.AddItem(loItem)

loItem = loItems.CreateItem()
loItem.Sku = "NewItem2"
loItem.Descript = "Second New Item Description"
loItem.Price = 100.00
loItems.AddItem(loItem)

loService.UploadInventoryItems(loItems)

The key here is the CreateArray method to which you pass the fully qualified .NET type name. You can find this name in Reflector and it's always the namespace plus the class name. So System.String is the System namespace and the String class. Above WebStoreService.wws_itemsRow is the WebStoreService namespace and then wws_itemsRow class. The text after the last . is always the class, the rest is the namespace.

Array usage goes beyond arrays passed as parameters. Many message objects - those objects that are passed or returned from Web Services - often contain embedded arrays. You can use ComArray objects on these objects as well as long as you use the wwDotnetBridge indirect methods to do so.

For example:

loInvoice = loService.DownloadInvoice("ccasd01ss1")

*** Turn loInvoice.LineItems into a ComArray
loLineItems = loService.oBridge.GetProperty(loInvoice,"LineItems")

FOR lnX = 0 to loLineItems.Count-1
   loLineItem = loLineItems.Item(lnX)
   ...
ENDFOR

Bottom line: When you are dealing with arrays always use ComArrays, and to access those ComArrays use wwDotnetBridge's method to get/set or invoke members on the .NET COM object.


© West Wind Technologies, 2004-2020 • Updated: 09/29/15
Comment or report problem with topic