Examing the generated Proxy Classes
After you have generated the Web Service Proxy classes successfully you see a dialog that lets you review what was generated and move the generated files to a new location:
Show Assembly in Reflector
Browsing the .NET assembly with .NET Reflector is extremely useful for more complex services as you can view the full Web service definition as a class browser type view. You can see the main service class as well as each of the related message classes and enumerated (restriction) types that the Web service publishes.
Here's what the Reflector view display looks like of the generated .NET assembly:
This tool is very useful for browsing types generated by the Web Service, especially if you need to create and work with generated complex types for parameters or return values on the service's methods.
Discovering Type Names in Reflector
One of the most important things that you need to do with complex Web Services is to instantiate .NET types and pass them to a Web Service method. You can find any type definition in the generated assembly with Reflector and discover its type signature (namespace.class). You can instantiate any of these types by looking at the Name property while highlighting the class. To use the type name in VFP:
loItem = loService.oBridge.CreateInstance("WebStoreService.wws_itemsRow") loItem.Sku="NEWITEM" loItem.Descript="New Item" ... *** Pass object parameter to Web Service loService.UploadInventoryItem(loItem)
>
>Any of the types in the generated .NET assembly can be instantiated in this fashion and so allow you to easily populate complex types easily. Remember that if you have nested complex types, that each lower level object property requires instantiation separately.
**Show generated FoxPro Proxy class**
You can also view the generated FoxPro proxy class. When you click the view PRG of the Proxy class you will find a generated class that looks something like this:
```foxpro
*** Dependencies - DO webstoreserviceproxy.prg
DO wwDotNetBridge
SET PROCEDURE TO webstoreserviceproxy ADDITIVE
*************************************************************
DEFINE CLASS WebStoreServiceProxy AS Custom
*************************************************************
*: Generated with West Wind .NET Web Service Proxy Generator
*: Created: 04/22/09 12:30:51 AM
*:
*: It's recommended you don't modify this class as it may be
*: regenerated. If you need customization use a subclass in
*: separate PRG file that overrides behavior.
*************************************************************
*** Stock Properties
oBridge = null
oService = null
cServiceUrl = [http://www.west-wind.com/wwstore/service/webstoreconsumerservice.asmx]
cWsdlUrl = [http://www.west-wind.com/wwstore/service/webstoreconsumerservice.asmx?WSDL]
cAssemblyPath = LOWER(FULLPATH([webstoreserviceproxy.dll]))
cErrorMsg = ""
lError = .F.
*** Holds any array based results
DIMENSION aResult[1]
************************************************************************
* Init
****************************************
*** Function:
*** Assume:
*** Pass:
*** Return:
************************************************************************
FUNCTION Init(llNoLoad)
IF !llNoLoad
this.LoadService()
ENDIF
ENDFUNC
************************************************************************
* LoadService
****************************************
*** Function:
*** Assume:
*** Pass:
*** Return:
************************************************************************
FUNCTION LoadService()
LOCAL loBridge as wwDotNetBridge
THIS.oBridge = CREATEOBJECT("wwDotNetBridge")
this.oBridge.Loadassembly(this.cAssemblyPath)
this.oService = this.oBridge.Createinstance("WebStoreService.WebStoreService")
*** For some reason accessing URL directly doesnt work - use indirect referencing
*this.oService.Url = this.cServiceUrl
this.oBridge.SetProperty(this.oService,"Url",this.cServiceUrl)
ENDFUNC
* Init
************************************************************************
* GetDescription
****************************************
FUNCTION GetDescription(Sku as String) as String
LOCAL loException as Exception, lvResult as String
THIS.lError = .F.
this.cErrorMsg = ""
lvResult = .F.
TRY
lvResult = this.oBridge.InvokeMethod(this.oService, "GetDescription", Sku)
CATCH to loException
llError = .T.
this.cErrorMsg = loException.Message
ENDTRY
RETURN lvResult
ENDFUNC
* GetDescription
************************************************************************
* DownloadInventoryItem
****************************************
FUNCTION DownloadInventoryItem(Sku as String) as wws_itemsRow
LOCAL loException as Exception, lvResult as wws_itemsRow
THIS.lError = .F.
this.cErrorMsg = ""
lvResult = .F.
TRY
lvResult = this.oBridge.InvokeMethod(this.oService, "DownloadInventoryItem", Sku)
CATCH to loException
llError = .T.
this.cErrorMsg = loException.Message
ENDTRY
RETURN lvResult
ENDFUNC
* DownloadInventoryItem
************************************************************************
* DownloadInventoryItems
****************************************
FUNCTION DownloadInventoryItems(Category as String) as wws_itemsRowArray
LOCAL loException as Exception, lvResult as wws_itemsRowArray
THIS.lError = .F.
this.cErrorMsg = ""
lvResult = .F.
TRY
*** lvResult will be ComArray object to represent the array
lvResult = this.oBridge.InvokeMethod(this.oService, "DownloadInventoryItems", Category)
CATCH to loException
llError = .T.
this.cErrorMsg = loException.Message
ENDTRY
RETURN lvResult
ENDFUNC
* DownloadInventoryItems
************************************************************************
* DownloadInventoryItemsDataSet
****************************************
FUNCTION DownloadInventoryItemsDataSet(Category as String) as DataSet
LOCAL loException as Exception, lvResult as DataSet
THIS.lError = .F.
this.cErrorMsg = ""
lvResult = .F.
TRY
lvResult = this.oBridge.InvokeMethod(this.oService, "DownloadInventoryItemsDataSet", Category)
*** Turn the result into a XmlAdapter - use loAdapter.Tables[0] to access cursors
lvResult = THIS.oBridge.DatasetToXmlAdapter(lvResult)
CATCH to loException
llError = .T.
this.cErrorMsg = loException.Message
ENDTRY
RETURN lvResult
ENDFUNC
* DownloadInventoryItemsDataSet
ENDDEFINE
The generated class basically uses wwDotNetBridge (oBridge property) to instantiate an instance of the Web Service .NET Proxy class (oService property) both of which are cached in the class initialization code. Each of the service methods then is wrapped into an Exception block that indirectly calls the Web Service .NET Proxy class, captures exceptions and returns result back to the client.
Some of the results are fixed up internally - notice that each call to the service methods is done via the wwDotNetBridge.InvokeMethod() method. This ensures that parameters and return values are actually handled inside of .NET and get around some of the FoxPro limitations of dealing with certain .NET types like arrays, Guids or any sort of value based/structure types.
The wrapper methods also handle special parameters by translating them into FoxPro types that make more sense. DataSet results are turned into FoxPro XMLAdapters for example and arrays are returned as a special ComArray .NET object that includes methods to manipulate that array from Visual FoxPro.
To call methods on this service then becomes a simple matter of instantiating the class and firing methods on it:
*** Load libraries
DO WebStoreServiceProxy
LOCAL loService as WebStoreServiceProxy
loService = CREATEOBJECT("WebStoreServiceProxy")
*** Call a method that returns an object
LOCAL loItem as WebStoreService.wws_itemsRow
loItem = loService.DownloadInventoryItem("WCONNECT50")
? loItem.Sku
? loItem.Descript
*** Service Method Returns a ComArray array wrapper for Items[]
loItems = loService.Downloadinventoryitems("")
FOR lnX = 1 TO loItems.Count
loItem = loItems.Item(lnX)
? loItem.Sku + " " + loItem.Descript + " " + TRANSFORM(loItem.Price)
ENDFOR
*** We can manipulate the ComArray by adding a new item
loNewItem = loItems.CreateItem() && Create a new instance of a child item
loNewItem.Sku = "NEWITEM"
loNewItem.Descript = "Some new Item"
loItems.AddItem(loNewItem)
*** Now send the whole array back to the server
loService.UploadIntoryItems(loItems)
*** Data Set result returns an XML Adapter
loAdapter = loService.DownloadInventoryItemsDataSet("")
IF ISNULL(loAdapter)
? loService.cErrorMsg
? "No data returned"
ENDIF
*** Dump first table to a cursor (or specify cursor name in 2nd parm)
loServer.oBridge.XmlAdapterToCursor(loAdapter)
BROWSE
Note that if you chose to run the Generator with local COM registration Intellisense should work for the .NET components, loItem should exhibit Intellisense in both the editor and from the command line. COM registration is optional and only recommended on your development machine to provide Intellisense. At runtime, no COM registration is required.
Open Folder of generated files
This option simply opens the folder where the proxy classes were generated. This lets you manually examine the generated files.
As the figure shows the generator creates a CSharp source file and compiles a .NET assembly (.dll) from the source file. The PRG is generated separately and contains the FoxPro code that calls the .NET assembly's service methods and uses the generated .NET message types.
Copy Files and Dependencies
After you've generated the files you can also let the generator create a 'distribution' copy for you, which copies all files required to run the generated FoxPro proxy class from a single folder location. In addition to the generated files discussed in the previous section this copy also copies wwDotNetBridge.dll, wwIpstuff.dll, wconnect.h, wwUtils.prg and wwDotnetBridge.prg to the specified directory.
For more information see the Files Required for Distribution and Compilation topic.
© West Wind Technologies, 2004-2020 • Updated: 09/29/15
Comment or report problem with topic