FoxPro and .NET Interop
Bug in wwDotNetBridge / Help with proxy generator
Gravatar is a globally recognized avatar based on your email address. Bug in wwDotNetBridge / Help with proxy generator
  Scott R
  All
  Jun 17, 2020 @ 10:04am

Hey Rick,

I'm using the proxy generator to do a SOAP integration my clients are wanting. It's going well until a method returns back a dataset. I can't figure out how to access the data in the object that's returned to VFP.

I've used Fidler to see the exact XML that's returned and it doesn't look crazy so I tried to call oTSO.oBridge.dataSetToCursors(oResp)and I'm getting an error:

My full code looks like:

DO tsoUnits

LOCAL oTSO, oResp 

oTSO = CREATEOBJECT("TSOUnits","V4")
oResp = oTSO.getUnitList(oToken.token)
IF !EMPTY(oTSO.cErrorMsg)
	oRet.errorMsg = oTSO.cErrorMsg
	RETURN oRet
ENDIF 

In the command window I was doing the oTSO.oBridge.datasettocursors(oResp)

Is this a known issue or would you recommend a better way to get to the data in the data set that's returned? Is there a way to get back the raw XML as a string I can manipulate?

I've also tried to do things like: oHold = oTSO.oBridge.getPropertyEx(oResp, 'Table[0]') and that errors out on me as well. I can get you the raw XML string (that I captured in Fiddler) if that helps point us in the right direction.

Here's the code in the C# file the proxy generator created if that helps?

/// <remarks/>
        [System.Web.Services.Protocols.SoapDocumentMethodAttribute("TSOAPI/GetUnitList", RequestNamespace="TSOAPI", ResponseNamespace="TSOAPI", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
        public System.Data.DataTable GetUnitList(string token) {
            object[] results = this.Invoke("GetUnitList", new object[] {
                        token});
            return ((System.Data.DataTable)(results[0]));
        }
Gravatar is a globally recognized avatar based on your email address. re: Bug in wwDotNetBridge / Help with proxy generator
  Rick Strahl
  Scott R
  Jun 17, 2020 @ 02:42pm

Old version?

As to DataSet/Table access it's possible but it's freaking ugly due to the multi-dimensional collections used.

There was a recent discussion regarding this here:

Access .NET DataSet from Dotnet in FoxPro

In general it's better to use the XML Adapter conversions. You can use DataSetToCursors(), but in your case you have a DataTable so that likely won't work.

Also offhand not sure if that particular function has made it into the Proxy tooling - I think that might be newer.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: Bug in wwDotNetBridge / Help with proxy generator
  Scott R
  Rick Strahl
  Jun 18, 2020 @ 06:15am

Hey Rick,

You gave me an 'experimental' wwDotNetBridge about a week ago in relation to the bug in serializing dateTimes in cursors so I don't think it's an old version problem.

From the article you linked, I was able to get it working. However, I was wondering if there's a way to get the properties by name instead of by index?

Basically instead of oTSO.oBridge.getPropertyEx(oRow, 'ItemArray[0]')

I want to do something like oTSO.oBridge.getPropertyEx(oRow, 'ItemArray.ID')

but it keeps erroring out on my to do the .ID (I know ID is one of the properties returned). Is there a way to do this?

Gravatar is a globally recognized avatar based on your email address. re: Bug in wwDotNetBridge / Help with proxy generator
  Rick Strahl
  Scott R
  Jun 18, 2020 @ 12:36pm

Not that I know of...

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: Bug in wwDotNetBridge / Help with proxy generator
  Scott R
  Rick Strahl
  Jun 18, 2020 @ 12:39pm

Fair enough. Figured it was worth asking. The product we're integrating in with has a history of changing the order of fields returned when they add a new one, which is why I'd rather go by the name than the index but I'll make it work.

Thanks for your help.

Gravatar is a globally recognized avatar based on your email address. re: Bug in wwDotNetBridge / Help with proxy generator
  Rick Strahl
  Scott R
  Jun 18, 2020 @ 01:24pm

The problem is the DataSet and DataRow are explicitly marked to be [ComVisible(false)] which means none of the interfaces automatically work over COM. Everything has to go through Reflection() which makes things much slower. The only thing that can access the data row value is the overridden indexer which is difficult to do with Reflection. There probably is a way but I'm not going to waste time on that because this is very very rare. These days everything lives in typed collections or string dictionaries which is more explicit and does work as you'd expect.

And just to clarify I would not recommend using direct table/dataset access via properties. It's bound to be considerably slower than the serialization except for very small tables due to the chatty nature of having to make a COM call + Reflection for each and every value retrieved. Making the one call to have the XML parsed is almost always quicker even though it seems very expensive.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: Bug in wwDotNetBridge / Help with proxy generator
  Rick Strahl
  Scott R
  Jun 18, 2020 @ 02:58pm

Ok so I took another look at how this works in wwdotnetbridge. It can deal with indexers but the problem with DataRow is that it's a multi-dimensional array like structure. It's not really an array or collection itself, but rather a plain object with an indexer. Normally you can do:

lcResult = loBridge.GetProperty(someObject,'someCollection["value"]')

And that works. For a DataRow though you have to do:

lcName = loBridge.GetProperty(loRow,'["name"]')

and it turns out that didn't work because the old code assumed there was a base property that identifies the collection/array (ie. someCollection in the first example).

With a little bit of tweaking I've made that work in the wwDotnetBridge.dll so you can now do:

do wwDotNetBridge
LOCAL loBridge as wwDotNetBridge
loBridge = GetwwDotnetBridge()

loNet = loBridge.CreateInstance("Westwind.WebConnection.TypePassingTests")
? loNet
loDs = loNet.GetDataSet()
? loDs
? loBridge.cErRORMSG



loTable = loBridge.GetProperty(loDs,"Tables[0]")
loRows = loBridge.GetProperty(loTable, "Rows")
? loBridge.ToString(loRows)

lnRecs = loBridge.GetProperty(loRows,"Count")
? lnRecs

FOR lnX = 0 TO lnRecs - 1
    loRow = loBridge.GetPropertyEx(loTable,"Rows[" + TRANS(lnX) +  "]")

    ? loBridge.GetProperty(loRow,'["name"]')
    ? loBridge.GetProperty(loRow,'["company"]')
    ? loBridge.GetProperty(loRow,'["entered"]')
ENDFOR

You can grab the WebConnection Experimental file again.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: Bug in wwDotNetBridge / Help with proxy generator
  Scott R
  Rick Strahl
  Jun 18, 2020 @ 03:04pm

Thanks Rick! I'll give it a try.

Gravatar is a globally recognized avatar based on your email address. re: Bug in wwDotNetBridge / Help with proxy generator
  Rick Strahl
  Scott R
  Jun 18, 2020 @ 04:55pm

Also just to clarify you should also be able to do:

loNet = loBridge.CreateInstance("Westwind.WebConnection.TypePassingTests")
loDs = loNet.GetDataSet()
loBridge.DataseToCursors(loDs)
BROWSE

This will create Cursors for each for the DataTable objects in a DataSet, which accomplishes essentially what the other code does, but likely is quicker and more efficient especially if you need to use all the data. Individual DataRow field access might be useful if you need to access just a few fields of a very wide table perhaps.

+++ Rick ---

© 1996-2020