Examing the generated Proxy Classes

about 5 minutes to read

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:

foxpro

loItem = loService.oBridge.CreateInstance("WebStoreService.wws_itemsRow") loItem.Sku="NEWITEM" loItem.Descript="New Item" ... *** Pass object parameter to Web Service loService.UploadInventoryItem(loItem)

foxpro
> >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:

foxpro
*** 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.

Next: Using the FoxPro Proxy Class to call the Web Service


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