2 Replies Latest reply on Aug 13, 2007 12:05 PM by nummsa

    Trouble with arguments in .NET objects

    nummsa
      I'm having a horrible time integrating with a 3rd party API in .NET 1.1 calling functions with arguments that are not simple datatypes. I understand the limitations of not being able to pass pointers/refs, but even simple datatypes I think are not working. It's impossible to debug because CF reports that the method with the supplied arguments was unable to be found. I've tried every iteration of JavaCast and think I fully understand the limitations of the .NET integration, but it's still impossible to know if the casting of specific arguments is getting fouled. I even look to see how CF expects a method's arguments to be cast by doing a simple CFDUMP on the object that contains the method and seeing how the cfdump reports the arguments to be cast. It almost appears as though .NET "bool" datatypes might be fouling it up - albeit I tried every iteration of JavaCast("boolean", ...) I could muster and the method is still not found. This seems to be the case with methods in a .NET object, overloaded constructors with arguments and even Set_Func(Value) functions.

      I tried to come up with a simple example of how this does not work, and the most generic I could come up with is trying to instantiate the System.DateTime with a specific date. I completely understand the fact that CF automatically can convert native CF dates to System.DateTime but my example shows the problem:
      <cfset arrivalDate = createObject(".NET", "System.DateTime").init(JavaCast("int", 2007), JavaCast("int", 9), JavaCast("int", 1))>

      If you look at the introspection/reflection of the System.DateTime object you'll see a simple constructor as: public DateTime(int year, int month, int day);

      If you try to use .init(2007, 9, 1) in the cfset for this object, you'll get: Unable to find a constructor for class System.DateTime that accepts parameters of type ( java.lang.String, java.lang.String, java.lang.String ).

      if you use .init(JavaCast("int", 2007), JavaCast("int", 9), JavaCast("int", 1)) in the cfset for this object you'll get: Unable to find a constructor for class System.DateTime that accepts parameters of type ( java.lang.Integer, java.lang.Integer, java.lang.Integer ).

      Clearly the claimed CF auto-conversion of CF integer -> java.lang.Integer -> System.Int32 does not work in this instance of trying to instantiate a System.DateTime. This also leads me to believe that there are other problems with automatic conversion of complex arguments even considering the limitations presented at: http://livedocs.adobe.com/coldfusion/8/htmldocs/dotNet_05.html#1163842

      Any help is much appreciated!
        • 1. Re: Trouble with arguments in .NET objects
          rupesh_kumar Adobe Employee
          Thats a special case you are hitting. .NET Primitive data type and DateTime are automatically converted to corresponding ColdFusion type and you work on those data as if they are coldfusion native types. You can not invoke any .NET functions on these data types.
          Try to use any other .NET class and you should be able to invoke them correctly.
          • 2. Re: Trouble with arguments in .NET objects
            nummsa Level 1
            Rupesh,

            Thanks for the response! I must elaborate a little more on the real problem I'm trying to get around to see if I can get some more light shed on this...

            I'm trying to invoke numerous methods from a 3rd party "API" which I cannot speak of in terms of programmatic completeness. As much as I've seen the code, via Reflector's disassembling greatness ( http://www.aisto.com/roeder/dotnet/), it looks rather complete. I keep encountering issues with trying to invoke certain methods from various classes in this API. I look for all data types to be properly cast, no references being passed in/out, etc. in these functions. Everything looks kosher from the code and the datatypes but I get the following CF error:

            The getRateForStayDate method was not found.
            Either there are no methods with the specified method name and argument types, or the getRateForStayDate method is overloaded with argument types that ColdFusion cannot decipher reliably. ColdFusion found 0 methods that matched the provided arguments. If this is a Java object and you verified that the method exists, you may need to use the javacast function to reduce ambiguity.

            I'll use this one example function, getRateForStayDate, and outline the code. The getRateForStayDate function has the following C# code:
            public virtual decimal getRateForStayDate(DateTime stayDate, SystemSettings settings, WebStayInfo stayValues, string ratePlanCode, string roomCode, bool isPackage)
            {
            if (stayDate.CompareTo(DateTime.MinValue) == 0)
            {
            throw new V1WebBusinessException("Stay date must be specified");
            }
            DateTime arrivalDate = stayValues.ArrivalDate;
            if (arrivalDate.CompareTo(DateTime.MinValue) == 0)
            {
            throw new V1WebBusinessException("Arrival Date must be specified");
            }
            short nights = stayValues.Nights;
            if (nights < 1)
            {
            throw new V1WebBusinessException("Nights must be greater than 0");
            }
            if (ratePlanCode == null)
            {
            throw new V1WebBusinessException("Rate plan code must be specified");
            }
            if ((roomCode == null) || roomCode.Equals(string.Empty))
            {
            throw new V1WebBusinessException("Room code must be specified");
            }
            if (isPackage)
            {
            Package package = (Package) this._packages[ratePlanCode];
            if (package == null)
            {
            throw new V1WebBusinessException("Package " + ratePlanCode + " not supported on web");
            }
            WebRoom room = package.getRoom(arrivalDate, nights, roomCode);
            if (room == null)
            {
            return decimal.Zero;
            }
            return Math.Round(decimal.Divide(Math.Round(room.StayTotal, 2), new decimal(nights)), 2);
            }
            Room room2 = this.getRoom(stayDate, roomCode, ratePlanCode);
            if (room2 == null)
            {
            throw new V1WebBusinessException("Room " + roomCode + " not supported on the web");
            }
            return room2.getRate(settings, stayDate, ratePlanCode, stayValues);
            }

            Seeing as this function is mostly exception conditions, the getRate() method at bottom is disassembled in C# as follows:
            public decimal getRate(SystemSettings settings, DateTime stayDate, string tariffCode, WebStayInfo stayvalues)
            {
            IList list = (IList) this._tariffs[stayDate];
            if (list != null)
            {
            if (tariffCode == null)
            {
            throw new ApplicationException("A Tariff Code Must Be Specified");
            }
            short count = (short) list.Count;
            for (short i = 0; i <= count; i = (short) (i + 1))
            {
            RoomTariff tariff = (RoomTariff) list ;
            if (tariff.TariffCode.Equals(tariffCode))
            {
            return tariff.getRate(settings, stayvalues);
            }
            }
            }
            return decimal.Zero;
            }

            The getRateForStayDate method originally called is the ONLY function in with that name in the class and not overloaded. The prototype for this function is:
            public virtual decimal getRateForStayDate(DateTime stayDate, SystemSettings settings, WebStayInfo stayValues, string ratePlanCode, string roomCode, bool isPackage)

            .. which equates to the following prototype when instantiated in CF:
            getRateForStayDate(System.DateTime, com.v1s.v1web.bll.SystemSettings, com.v1s.v1web.bll.WebStayInfo, java.lang.String, java.lang.String, boolean)

            The two arguments that are not automatically converted are: SystemSettings and WebStayInfo. These arguments are two custom classes in this 3rd party API. I instantiate each of these objects prior to the method call in question and the CFDUMP introspection on these two objects shows proper data types as well as being able to run various methods and Get_X() functions to make sure they work. I checked every argument being passed to the function in question and the datatypes match when attempting:
            <cfset webAvail.getRateForStayDate(CreateDate(2007, 9, 1), v1webSystemSettings, webStayInfo, "", "", JavaCast("boolean", "no"))>

            This is not the only function that I'm having this problem trying to invoke within this 3rd party API. I've tried every way to javacast() all the arguments but the custom .NET datatypes that need to be passed in. For all I know - that might be the root of the problem. I see nothing passed by reference, except in the .NET callstack, a couple functions in after the call to getRateForStayDate, a reference is used for a SQL abstraction layer as a sql connection object. Unsure if that might cause trouble in this case.

            Thanks in advance for any help/suggestions, and for the help thus far.

            On another hand, any way to get access back to the prerelease forums for CF8 by any chance? There was a great CF<->.NET integration folder on there that I would like to scour.