huysentruitw / SapNwRfc

SAP NetWeaver RFC library for .NET 5, .NET Core and .NET Framework
MIT License
149 stars 43 forks source link

Incorrect number of arguments supplied for call to method 'Char get_Chars(Int32)' (Parameter 'property') #97

Open jefferson-cruz opened 5 months ago

jefferson-cruz commented 5 months ago

When the object has properties that are arrays of primitive types, an exception with the message "Incorrect number of arguments supplied for call to method 'Char get_Chars(Int32)' (Parameter 'property')" is thrown.

System.ArgumentException: Incorrect number of arguments supplied for call to method 'Char get_Chars(Int32)' (Parameter 'property')
   at System.Linq.Expressions.Expression.Property(Expression expression, PropertyInfo property)
   at SapNwRfc.Internal.InputMapper.BuildApplyExpressionForProperty(PropertyInfo propertyInfo, Expression interopParameter, Expression dataHandleParameter, Expression inputParameter)
   at SapNwRfc.Internal.InputMapper.<>c__DisplayClass4_0.<BuildApplyAction>b__0(PropertyInfo propertyInfo)
   at System.Linq.Enumerable.SelectArrayIterator2.MoveNext()
   at System.Linq.Enumerable.WhereEnumerableIterator1.ToArray()
   at SapNwRfc.Internal.InputMapper.BuildApplyAction(Type type)
   at System.Collections.Concurrent.ConcurrentDictionary2.GetOrAdd(TKey key, Func2 valueFactory)
   at SapNwRfc.Internal.InputMapper.Apply(RfcInterop interop, IntPtr dataHandle, Object input)
   at SapNwRfc.Internal.Fields.TableField`1.Apply(RfcInterop interop, IntPtr dataHandle)
   at lambda_method154(Closure, RfcInterop, IntPtr, Object)
   at SapNwRfc.Internal.InputMapper.Apply(RfcInterop interop, IntPtr dataHandle, Object input)
   at SapNwRfc.SapFunction.Invoke(Object input)
   at SapNwRfc.SapFunction.Invoke[TOutput](Object input)
   at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
   at IntegraSky.Agent.Sap.Rfc.ExecuteRfcService.ExecuteCommandToJson(TerminalParameters terminalParameters, RfcAccount rfcAccount, RfcCommand rfcCommand)

Example of the request

{
   "I_REPRESENTANTE": "000000",
   "I_CLIENTE": [
      "0000000000"
   ],
   "I_FOTO": []
}

I noticed that the error occurs in the TableField class, when it executes the Apply method, which ends up calling InputMapper.Apply(RfcInterop interop, IntPtr dataHandle, object input).

Does SapNwRfc support array of primitive types or is this not part of the project scope?

tom-j-irvine commented 5 months ago

What does your C# parameter class look like? I would expect it to look something like the following. The array parameter needs to be another object and if it doesn't have a name, the SapName attribute can set it to an empty string.

class InputParameters
{
    [SapName("I_REPRESENTANTE")]
    public string Representante { get; set; }

    [SapName("I_CLIENTE")]
    public ClienteParameter[] Clients { get; set; }
}

class ClienteParameter
{
    [SapName("")]
    public string Client { get; set; }
}
jefferson-cruz commented 5 months ago

In fact, my service receives REST requests that contain JSON in the body. Later, I transform the JSON into a dynamic object in C# and call sapFunction.Invoke<dynamic>(dynamicObject). Because it has this characteristic, there is no way to predict the model that will be sent by the customer.

What does your C# parameter class look like? I would expect it to look something like the following. The array parameter needs to be another object and if it doesn't have a name, the SapName attribute can set it to an empty string.

class InputParameters
{
    [SapName("I_REPRESENTANTE")]
    public string Representante { get; set; }

    [SapName("I_CLIENTE")]
    public ClienteParameter[] Clients { get; set; }
}

class ClienteParameter
{
    [SapName("")]
    public string Client { get; set; }
}
tom-j-irvine commented 5 months ago

SAP RFC functions have strongly-typed input and output parameters. You can't just feed them dynamic wads of data and hope that everything works out. In SAP, the function module will have certain input and output parameters. As described in the documentation, you need map these to C#: https://github.com/huysentruitw/SapNwRfc?tab=readme-ov-file#call-function-with-input-and-output-parameters (or at least all of them you want to use).

If you have some random json you need to feed into a SAP RFC function call, you'll need to transform that data into the appropriate parameters for the function and provide a strongly-typed object to hold the result.

I can provide more input if you provide a full description of the SAP function module being called (screen shots of the Import, Export, Changing, and Tables tabs would be best). These will define what you need to pass in as parameters and what you will receive back as a response.