West Wind .NET Tools and Demos
dotNet Bridge getProperty for type VFP doesn't support
Gravatar is a globally recognized avatar based on your email address. dotNet Bridge getProperty for type VFP doesn't support
  Scott R
  All
  Sep 19, 2019 @ 10:19am

Rick,

I'm using your West Wind Web Service Proxy Generator for some SOAP stuff I'm doing. This is working well except I can't figure out how to get a value from the return Object.

My code looks like:

       DO TeleTracNavDirServiceProxy
	
	LOCAL oTeleTrac

	*** Create Proxy Instance & specify .NET version
	oTeleTrac = CREATEOBJECT("TeleTracnavDirServiceProxy", "V4")

	*** Call your methods and retrieve result
	LOCAL oAuthObj, oAuthResp, m.authToken
	oAuthObj = oTeleTrac.oBridge.createInstance('Service.DoLoginRequest') &&CREATEOBJECT('empty')
	
	* Add the Session  prop to the oAuthObj
	oTeleTrac.oBridge.createInstanceOnType(oAuthObj, 'Session', 'Service.SessionInfo')

	oUserInfo = oTeleTrac.oBridge.createInstance('Service.UserCredentialInfo')
	oUserInfo.username = ALLTRIM(tFDIRCred.vtrklogin)
	oUserInfo.password = ALLTRIM(tFDIRCred.vtrkpwd)
	
	oAuthObj.UserCredential = oUserInfo

	oAuthResp = oTeleTrac.DoLogin(oAuthObj)
	IF !EMPTY(oTeleTrac.cErrorMsg)
		* Crap!
		oret.errormsg = oTeleTrac.cErrorMsg
		RETURN oRet
	ENDIF 

	*oRet.token = oAuthResp.sessionId

My Problem is once I have my resp back I need to access a VERY nested property that is of the type Guid

I've tried all of the following but can't get it to work

* Full 'path' to prop is: oAuthResp.SecurityProfile.Session.SessionId

?oTeleTrac.oBridge.getPropertyex(oAuthResp, SecurityProfile.Session.SessionId)
?oTeleTrac.oBridge.getProperty(oAuthResp, SecurityProfile.Session.SessionId)
?oTeleTrac.oBridge.getProperty(oAuthResp.SecurityProfile.Session, SessionId)

Is there something I'm missing or what's the best way to access a property that's not a simple type that VFP has?

Thanks.

Gravatar is a globally recognized avatar based on your email address. re: dotNet Bridge getProperty for type VFP doesn't support
  Rick Strahl
  Scott R
  Sep 19, 2019 @ 11:17am

Guid is a value type and not COM accessible so it can't be accessed from FoxPro directly via COM.

What you need to do basically is retrieve the property with .GetProperty() which will return the Guid as a ComValue object from which you can get the string:

loComValue = oTeleTrac.oBridge.getPropertyex(oAuthResp, "SecurityProfile.Session.SessionId")
lcGuid = loComValue.GetGuid()

Updated the GetGuid() topic in the documentation:

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: dotNet Bridge getProperty for type VFP doesn't support
  Scott R
  Rick Strahl
  Sep 19, 2019 @ 11:36am

Rick,

Thanks for the quick response. Unfortunately that doesn't seem to be it.

I tried

oHold = oTeleTrac.oBridge.getPropertyex(oAuthResp, "SecurityProfile.Session.SessionId")
?oHold.GetGuid()

and I got Unknown name

I also tried oHold.ToString() and that just gave me Westwind.WebConnection.ComGuid

Based on the .Net Reflector (below), I also tried

oHold = oTeleTrac.oBridge.getPropertyex(oAuthResp, "SecurityProfile.Session")
?oHold.SessionInfo()

but to no avail.

Looking at it in the .Net Reflector, 'Session' is defined as:

[Serializable, DebuggerStepThrough, DesignerCategory("code"), XmlType(Namespace="http://onlineavl2.navmanwireless.com/0907/"), GeneratedCode("wsdl", "4.6.1590.0")]
public class SessionInfo
{
    // Fields
    [XmlElement(Order=0)]
    public Guid SessionId;

    // Methods
    public SessionInfo();
}


and following the Guid link takes me to:

[Serializable, StructLayout(LayoutKind.Sequential), ComVisible(true)]
public struct Guid : IFormattable, IComparable, IComparable<Guid>, IEquatable<Guid>
{
    public static readonly Guid Empty;
    private int _a;
    private short _b;
    private short _c;
    private byte _d;
    private byte _e;
    private byte _f;
    private byte _g;
    private byte _h;
    private byte _i;
    private byte _j;
    private byte _k;
    public Guid(byte[] b);
    [CLSCompliant(false)]
    public Guid(uint a, ushort b, ushort c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k);
    private Guid(bool blank);
    public Guid(string g);
    public Guid(int a, short b, short c, byte[] d);
    public Guid(int a, short b, short c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k);
    private static int TryParse(string str, ref int parsePos, int requiredLength);
    private static string EatAllWhitespace(string str);
    private static bool IsHexPrefix(string str, int i);
    public byte[] ToByteArray();
    public override string ToString();
    public override int GetHashCode();
    public override bool Equals(object o);
    public bool Equals(Guid g);
    private int GetResult(uint me, uint them);
    public int CompareTo(object value);
    public int CompareTo(Guid value);
    public static bool operator ==(Guid a, Guid b);
    public static bool operator !=(Guid a, Guid b);
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern void CompleteGuid();
    public static Guid NewGuid();
    public string ToString(string format);
    private static char HexToChar(int a);
    private static int HexsToChars(char[] guidChars, int offset, int a, int b);
    public string ToString(string format, IFormatProvider provider);
    static Guid();
}

 
Expand Methods
 

I know the value is there because when I do _cliptext = oTeleTrac.oBridge.ToXML(oAuthResp.SecurityProfile.Session)

I can see the SessionId (Guid)

<?xml version="1.0" encoding="utf-8"?>
<SessionInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <SessionId xmlns="http://onlineavl2.navmanwireless.com/0907/">81ceb8af-52da-49f3-8e42-f553ab8ce300</SessionId>
</SessionInfo>

But I can't seem to just access the dumb thing.

Is there something obvious I'm missing?

Thanks.

Gravatar is a globally recognized avatar based on your email address. re: dotNet Bridge getProperty for type VFP doesn't support
  Rick Strahl
  Scott R
  Sep 19, 2019 @ 09:59pm

Are you sure your signature is correct?

Walk the hierarchy and look at each object along the way. IOW, make sure .Session is an object of the right type - use .ToString() on that. My guess based on what you describe is that somewhere along the hierarchy you have an invalid name or another object that can't be accessed (perhaps another struct in the in-between objects?). Get each object individually and .ToString() on each. And check for error messages along the way.

If the data is a proxy object you are setting up realize that each object has to be created - it may be null.

oHold.SessionInfo() is not a method something you can call - that's the constructor() for the class - so that makes sense. Make sure the ref is not null and check error messages.

+++ Rick --

Gravatar is a globally recognized avatar based on your email address. re: dotNet Bridge getProperty for type VFP doesn't support
  Scott R
  Rick Strahl
  Sep 20, 2019 @ 12:38pm

Rick,

I've walked down the line and verified all types with the .ToString() and everything looks right.

I'm giving up on the just get property as I can't see anything wrong based on what you said. Instead, I'm going to try the .toJSON() method. The oBridge.toXML() works but then I can't just do xmlToCursor() as VFP can't figure out the types.

Instead, I'm trying to use the .toJSON() method but I'm getting an error that says:

OLE IDispatch exception code 0 from wwDotNetBridge: Could not load file or assembly 'NewtonSoft.JSON, Version=6.0.0.0,....

I found your post (https://west-wind.com/wconnect/weblog/ShowEntry.blog?id=927) on using the config file to change the dependancy version but I must be doing something wrong.

Since I'm current running in vfp I created a vfp9.exe.config file in my project directory (not VFP directory). I also placed newtonSoft.Json.dll in the same directory.

I keep getting the error that it can't find version 6.0.0.0. What did I screw up in the config file?

<!-- NOTE: This is so Rick Strahl's dot net bridge uses our version of newtonSoft.json
	See https://west-wind.com/wconnect/weblog/ShowEntry.blog?id=927 -->
<?xml version="1.0"?>
<configuration>
  <startup>   
	<!-- <supportedruntime version="v4.0.30319"/> -->
	<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
	<!-- supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" -->    
    <!-- supportedRuntime version="v2.0.50727"/ -->    
  </startup>
  <runtime>
      <loadFromRemoteSources enabled="true"/>
  </runtime>
  
  <runtime>    
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="11.0.2" />
      </dependentAssembly>
	</assemblyBinding>      
  </runtime>
</configuration>

I'm not sure if version '11.0.2' is correct since everything I see in your example is 4 long (ie. 6.0.0.0)

Looking at the details on the .dll i have File version: 11.0.2.21921 and Product version: 11.0.2 Which version am I supposed to use? or is my config file in the wrong spot?

Thanks again for all your help with this.

Gravatar is a globally recognized avatar based on your email address. re: dotNet Bridge getProperty for type VFP doesn't support
  Scott R
  Rick Strahl
  Sep 20, 2019 @ 01:04pm

Rick,

After reading another thread on the west wind message board, I realized that vfp9.exe.config must be in the same place as vfp9.exe so I moved it there.

I also set the newVersion="11.0.2.21924" (which I think is right?)

However, now I can't start VFP.

When I try to run the exe I get an error that says

The application has failed to start because its side-by-side configuration file is incorrect. Please see the application event log or use the command-line sxstrace.exe tool for more detail..

If I rename the config file to vfp9.exe.config2 I can get into VFP again. Did I screw something up that bad in my vfp9.exe.config file or am I missing something obvious?

Thanks.

Gravatar is a globally recognized avatar based on your email address. re: dotNet Bridge getProperty for type VFP doesn't support
  Rick Strahl
  Scott R
  Sep 20, 2019 @ 01:15pm

The version number should be for all versions below 11. But I think the way JSON .NET is versioned it's only versioned by its minor numbers rather than the full count.

You shouldn't really need that at all if you're using the Proxy generator - it should only be necessary if you're using another component that requires a different version of the JSON.NET. For Proxy generated components just use the DLL that wwDotnetBridge provides and remove the version forwarding from web.config.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: dotNet Bridge getProperty for type VFP doesn't support
  Rick Strahl
  Scott R
  Sep 20, 2019 @ 01:17pm

So I took a look at your scenario more closely and I can confirm it's not working. I'm not sure why GetProperty() on the Guid fails, but I'm looking into it. It looks like perhaps the pre/post processing is not picking up the Guid as a specially handled type in the same way as method calls are.

Stay tuned.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: dotNet Bridge getProperty for type VFP doesn't support
  Scott R
  Rick Strahl
  Sep 20, 2019 @ 01:38pm

Rick,

Glad I'm not going crazy. Thanks for looking into this! Please let me know what you find.

Gravatar is a globally recognized avatar based on your email address. re: dotNet Bridge getProperty for type VFP doesn't support
  Rick Strahl
  Scott R
  Sep 20, 2019 @ 01:46pm

Ok so I found the problem. The issue is that currently wwDotnetBridge returns a ComGuid object, not ComValue. This is a legacy object that is documented but isn't really supposed to be used any longer.

So here's what I did:

public Session GetGuidOnObject()
{
    var session = new Session() {Guid = Guid.NewGuid()};
    return session;
}

public class Session
{
    public Guid Guid { get; set; }
}

Then to call it from FoxPro:

LOCAL loBridge as wwDotNetCoreBridge
loBridge = GetwwDotnetBridge()
loNet = loBridge.CreateInstance("Westwind.WebConnection.TypePassingTests")

loSession = loNet.GetGuidOnObject()
? loSession.ToString()  && good

*** Returns ComGuid instance
loGuidValue = loBridge.GetProperty(loSession,"Guid")
? loGuidValue.GuidString   && this contains the Guid

This should work with the code you currently have.

Now - that said, I actually am going to change this in wwDotnetBridge. The Guid should return a ComValue object not a ComGuid so that it's consistent with other 'non-supported' values. I'm pretty sure that although this is a breaking change there are going to be very few people if any affected by this because the return of the ComGuid is actually not documented (hence my own confusion 😃) about this.

So using the updated syntax:

*** Returns ComGuid instance
loGuidValue = loBridge.GetProperty(loSession,"Guid")
? loGuidValue.GetGuid();

I'm updating the WebConnection preview files at:

https://west-wind.com/files/WebConnectionExperimental.zip

You can grab the latest wwDotnetBridge files from there.

Gravatar is a globally recognized avatar based on your email address. re: dotNet Bridge getProperty for type VFP doesn't support
  Scott R
  Rick Strahl
  Sep 20, 2019 @ 01:53pm

Rick,

That worked! Thanks for your help with this.

Gravatar is a globally recognized avatar based on your email address. re: dotNet Bridge getProperty for type VFP doesn't support
  Rick Strahl
  Scott R
  Sep 20, 2019 @ 04:00pm

Just as a heads up I recommend you use the new DLL so that this code won't break when a newer version of wwdotnetbridge shows up.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: dotNet Bridge getProperty for type VFP doesn't support
  Rick Strahl
  Scott R
  Sep 20, 2019 @ 04:11pm

Re: Assembly Binding Redirect

Your assembly binding redirect isn't working because JSON .NET has both an File Version and an Assembly Version which happen to be different. The one in the redirects is the Assembly Version. Due to compatbility issues JSON.NET always keeps a single round assembly version number and the .0.0.0 version and file versions that are minor updates.

So the version for recent JSON.NET Versions is 11.0.0.0.

You can find out the assembly version in Reflector:

or any other tool that can read the .NET version information.

<?xml version="1.0"?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.62" />
  </startup>
  <runtime>
      <loadFromRemoteSources enabled="true"/>
  </runtime>
  
  <system.net>    
    <connectionManagement>
      <add address="*" maxconnection="80" />
    </connectionManagement>
  </system.net>


  <runtime>    
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-11.0.0.0" newVersion="11.0.0.0" />
      </dependentAssembly>
	  </assemblyBinding>       
  </runtime>
</configuration>

This works for me when calling .ToJson() on a .NET object.

Actually - in most cases these days I don't actually use a .config file at all, but you do need it for the LoadFromRemoteSources for network loaded binary files (EXE or DLLs). Otherwise you can usually skip the .config file.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: dotNet Bridge getProperty for type VFP doesn't support
  Scott R
  Rick Strahl
  Sep 23, 2019 @ 06:46am

Rick,

I grabbed the new .dll (and .prg). Thanks.

Running into another issue still related to the Guid.

Once I have the guid, I have to set it on every subsequent call and I can't quite figure out how to do that. I've tried both of the following and one errors out (I believe because the Guid was a string at the point thanks to .GetGuid()) but I also can't get it to work using .setProperty

Basically, I'm doing:


oAuthObj = oGPS.oDotNet.oBridge.createInstance('Service.DoLoginRequest') 
		
		* Add the Session  prop to the oAuthObj (not mentioned in the WSDL but needed according to Teletrac support peeps)
		oGPS.oDotNet.oBridge.createInstanceOnType(oAuthObj, 'Session', 'Service.SessionInfo')
		*oGPS.oDotNet.oBridge.setPropertyEx(oAuthObj, 'Session.SessionId', oAuthToken.token) && Errors out becuase oAuthToken.token is a string 
		
		oGPS.oDotNet.oBridge.setProperty(oAuthObj, 'Session.SessionId', oGPS.oAuthToken.SecurityProfile.Session.SessionId) && Session.SessionId is a Guid

When I do this, I get an error in VFP that says Function argument value, type or count is invalid Not sure how to track this down or the proper way to set a Guid value via Dot Net? I know the Guid is valid because this works:

oHold = oGPS.oDotNet.oBridge.getProperty(oGPS.oAuthToken, 'SecurityProfile.Session.SessionId')
?oHold.GetGuid()

So how do I go about setting it from one Object onto another one?

I found https://webconnection.west-wind.com/docs/_35u03psei.htm That mentioned the setValueFromProperty but you don't actually give an exampe of using it. Instead you give an example of SetValueFromInvokeMethod

Thanks.

Gravatar is a globally recognized avatar based on your email address. re: dotNet Bridge getProperty for type VFP doesn't support
  Rick Strahl
  Scott R
  Sep 23, 2019 @ 10:09am

You need to pass the Guid as a ComValue - basically the same thing from getting the property in reverse:

loGuid = loBridge.CreateComValue()
loGuid.SetGuid(lcGuidString)

loBridge.SetProperty(oAuthObj, 'Session.SessionId', loGuid)

Just to clarify how and why: .NET has a fixed static signature that Reflection has to match when you call or set a property. When you call with string for the Guid, you're basically calling with an invalid, missing signature which is why it fails. Reflection doesn't know before the call what's available and simply uses the signature that you provide by way of the parameters or assignment values.

The workaround for wwDotnetBridge is that we can set a ComValue with the actual value we want to pass, and that triggers wwDotnetBridge to determine the type that you really intend to pass. So you SetGuid() then the Value is a Guid which is then used. And that works.

But it's cumbersome at times because you have to be aware when this is required. Basically with any Value type (a Guid is a Value type), any .NET generic type, enums, longs etc. that aren't supported over COM this explict workaround is required.

It requires some inside knowledge that especially bites people who are new. Even when you know it's easy to forget, and it's difficult to figure out how to get it to work as it's not discoverable other than searching here or in the docs.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: dotNet Bridge getProperty for type VFP doesn't support
  Scott R
  Rick Strahl
  Sep 24, 2019 @ 06:25am

Rick,

Thanks for the detailed response. Seems to be working and I'll keep the value types in mind.

Thanks again for all of your help with this.

Gravatar is a globally recognized avatar based on your email address. re: dotNet Bridge getProperty for type VFP doesn't support
  Scott R
  Rick Strahl
  Sep 25, 2019 @ 10:13am

Rick,

Sorry, one more question for you. I've hit another snag with the Guids. I have a property that I have to set that is a Guid Array. How do I go about doing this?

I was doing:

oGuid = oGPS.oDotNet.oBridge.createComValue()
oGuid.SetGuid(oHold.getGuid())		
oGPS.oDotNet.oBridge.setProperty(oReq, 'IDs', oGuid) && oReq.IDs is a Guid[]

But I got an error that said:

Object of type 'System.Guid' cannot be convert to type 'System.Guid[]'...

How do I create an array and make sure it's of type Guid?

Thanks.

Gravatar is a globally recognized avatar based on your email address. re: dotNet Bridge getProperty for type VFP doesn't support
  Rick Strahl
  Scott R
  Sep 25, 2019 @ 11:01am

You need to create a ComArray, then add the ComValue Guid objects to the array.

loGuidArray = loBridge.CreateArray("System.Guid")
loGuid = loBridge.CreateValue()
loGuid.SetGuid(lcGuidString)

loGuidArray.AddItem(loGuid)

loBridge.InvokeMethod(oObj,"PassGuidArrayMethod",loGuidArray)

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: dotNet Bridge getProperty for type VFP doesn't support
  Scott R
  Rick Strahl
  Sep 25, 2019 @ 11:40am

Rick,

I was missing the CreateArray("System.Guid") part. I guess I missed that in reading the array docs for dotNetBridge.

Thanks.

© 1996-2019