You can use .NET Open Client DATASET and TABLE parameters to send/receive datasets and temp-tables to/from the application server, as shown in the following example code.

ABL code

OutDataSet.p
DEFINE TEMP-TABLE ttCust 
        FIELD CustNum LIKE Customer.Custnum 
        FIELD NAME LIKE Customer.NAME 
        FIELD Address LIKE Customer.Address 
        FIELD City LIKE Customer.City 
        FIELD CreditLimit LIKE Customer.CreditLimit .
        
DEFINE DATASET myDS FOR ttCust.
        
DEFINE INPUT PARAMETER minCredit AS INTEGER.
DEFINE INPUT PARAMETER maxCredit AS INTEGER.
DEFINE OUTPUT PARAMETER DATASET FOR  myDS.
InpOutDataSet.p
DEFINE TEMP-TABLE ttCust 
        FIELD CustNum LIKE Customer.Custnum 
        FIELD NAME LIKE Customer.NAME 
        FIELD Address LIKE Customer.Address 
        FIELD City LIKE Customer.City 
        FIELD CreditLimit LIKE Customer.CreditLimit .
        
DEFINE DATASET myDS FOR ttCust.
        
DEFINE INPUT PARAMETER moreCredit AS INTEGER.
DEFINE INPUT-OUTPUT PARAMETER DATASET FOR  myDS.
InpDataSet.p
DEFINE TEMP-TABLE ttCust 
        FIELD CustNum LIKE Customer.Custnum 
        FIELD NAME LIKE Customer.NAME 
        FIELD Address LIKE Customer.Address 
        FIELD City LIKE Customer.City 
        FIELD CreditLimit LIKE Customer.CreditLimit .
        
DEFINE DATASET myDS FOR ttCust.
        
DEFINE INPUT PARAMETER DATASET FOR  myDS.
OutTable.p
DEFINE TEMP-TABLE ttCust 
        FIELD CustNum LIKE Customer.Custnum 
        FIELD NAME LIKE Customer.NAME 
        FIELD Address LIKE Customer.Address 
        FIELD City LIKE Customer.City 
        FIELD CreditLimit LIKE Customer.CreditLimit .
        

DEFINE INPUT PARAMETER minCredit AS INTEGER.
DEFINE INPUT PARAMETER maxCredit AS INTEGER.
DEFINE OUTPUT PARAMETER TABLE FOR  ttCust.
InpOutTable.p
DEFINE TEMP-TABLE ttCust 
        FIELD CustNum LIKE Customer.Custnum 
        FIELD NAME LIKE Customer.NAME 
        FIELD Address LIKE Customer.Address 
        FIELD City LIKE Customer.City 
        FIELD CreditLimit LIKE Customer.CreditLimit .
        
DEFINE INPUT PARAMETER moreCredit AS INTEGER.
DEFINE INPUT-OUTPUT PARAMETER TABLE FOR ttCust.
InpTable.p
DEFINE TEMP-TABLE ttCust 
        FIELD CustNum LIKE Customer.Custnum 
        FIELD NAME LIKE Customer.NAME 
        FIELD Address LIKE Customer.Address 
        FIELD City LIKE Customer.City 
        FIELD CreditLimit LIKE Customer.CreditLimit .
        
DEFINE INPUT PARAMETER TABLE FOR ttCust.

OpenAPI code

// EXAMPLES FOR DATASET and TABLE Params

using System.Data;
using Progress.Open4GL;
using Progress.Open4GL.DynamicAPI;
using Progress.Open4GL.Proxy;

DataSet myDSet;

try
{
    // Connect to the AppServer
    Connection myConn = new Connection ("http://<host>/apsv", "", "", "");

    OpenAppObject openAO = new OpenAppObject(myConn, "");

    // Set Session model for state-free
    myConn.SessionModel = 1;

    System.Int32 minCreditLimit = 1500;
    System.Int32 maxCreditLimit = 2000;
    System.Int32 moreCredit = 3000;

    DataTable myDT;

    /////////////////////////////////////////////////////
    /// Example code passing DataSet as output parameter


    // Create the ParamArray
    ParamArray parms = new ParamArray(3);

    // Set up input parameters
    parms.AddInteger(0, minCreditLimit, ParamArrayMode.INPUT);
    parms.AddInteger(1, maxCreditLimit, ParamArrayMode.INPUT);

    // Set up Out parameters
    ProDataSetMetaData dsetMetaData = createDSetMetaData();
    parms.AddDataset(2, null, ParamArrayMode.OUTPUT, dsetMetaData);

    // Run the procedure
    System.Console.Out.WriteLine("Calling OutDataSet");
    openAO.RunProc("OutDataSet.p", parms);

    // Retrieve data and print
    myDSet = (DataSet)parms.GetOutputParameter(2);
    printDataSet(myDSet, false);

    /////////////////////////////////////////////////////
    /// Example code passing DataSet as input-output parameter


    parms = new ParamArray(2);

    // Set up input parameters
    parms.AddInteger(0, moreCredit, ParamArrayMode.INPUT);

    // Set up Out parameters
    parms.AddDataset(1, myDSet, ParamArrayMode.INPUT_OUTPUT, dsetMetaData);

    System.Console.Out.WriteLine("Calling InpOutDataSet.p");
    openAO.RunProc("InpOutDataSet.p", parms);

    // Retrieve data and print
    myDSet = (DataSet)parms.GetOutputParameter(1);
    printDataSet(myDSet, false);

    /////////////////////////////////////////////////////////////////
    /// Example code passing DataSet as input parameter


    parms = new ParamArray(1);

    parms.AddDataset(0, myDSet, ParamArrayMode.INPUT, dsetMetaData);

    System.Console.Out.WriteLine("Calling InpDataSet.p");
    openAO.RunProc("InpDataSet.p", parms);

    System.Console.Out.WriteLine("Finished InpDataSet.p");

    //////////////////////////////////////////////////////////////
    /// Example code passing Table as output parameter


    System.Console.Out.WriteLine("\n\nTempTable Examples");

    // Create the ParamArray
    parms = new ParamArray(3);

    // Set up input parameters
    parms.AddInteger(0, minCreditLimit, ParamArrayMode.INPUT);
    parms.AddInteger(1, maxCreditLimit, ParamArrayMode.INPUT);

    // Set up Out parameters
    TempTableMetaData tableMetaData = createTableMetaData(); 
    //Must specify specify metadata
    parms.AddTable(2, null, ParamArrayMode.OUTPUT, tableMetaData);

    // Run the procedure
    System.Console.Out.WriteLine("Calling OutTable.p");
    openAO.RunProc("outTable.p", parms);

    // Retrieve data and print
    myDT = (DataTable)parms.GetOutputParameter(2);
    System.Console.Out.WriteLine("DataTable " + myDT.TableName + " contains " + myDT.Rows.Count + " rows.");


    /////////////////////////////////////////////////////////////////
    /// Example code passing Table as input-output parameter


    parms = new ParamArray(2);

    // Set up input parameters
    parms.AddInteger(0, moreCredit, ParamArrayMode.INPUT);

    // Set up input-output parameters
    parms.AddTable(1, myDSet.Tables[0], ParamArrayMode.INPUT_OUTPUT, tableMetaData);

    System.Console.Out.WriteLine("Calling InpOutTable.p");
    openAO.RunProc("InpOutTable.p", parms);

    // Retrieve data and print
    myDT = (DataTable)parms.GetOutputParameter(1);
    System.Console.Out.WriteLine("DataTable " + myDT.TableName + " contains " + myDT.Rows.Count + " rows.");

    /////////////////////////////////////////////////////////////////
    /// Example code passing Table as input parameter

    parms = new ParamArray(1);

    parms.AddTable(0, myDSet.Tables[0], ParamArrayMode.INPUT, tableMetaData);

    System.Console.Out.WriteLine("Calling InpTable.p");
    openAO.RunProc("InpTable.p", parms);
    System.Console.Out.WriteLine("Finished InpTable.p");
}
catch (System.Exception e)
{
    System.Console.Out.WriteLine("Error:" + e.Message);
}


///////////////////////////////////////////////////////////////////////////

ProDataSetMetaData createDSetMetaData()
{
    ProDataSetMetaData proDGMD = new ProDataSetMetaData("customerDS", "");

    TempTableMetaData custTT = createTableMetaData();

    proDGMD.AddDataTable(custTT);

    return proDGMD;
}

TempTableMetaData createTableMetaData()
{
    TempTableMetaData custTT = new TempTableMetaData("custTT", "", 5, false, 0, "", "", "");

    custTT.SetFieldMetaData(1, "CustNum", 0, Parameter.PRO_INTEGER, 0, 0);
    custTT.SetFieldMetaData(2, "Name", 0, Parameter.PRO_CHARACTER, 1, 0);
    custTT.SetFieldMetaData(3, "Address", 0, Parameter.PRO_CHARACTER, 2, 0);
    custTT.SetFieldMetaData(4, "City", 0, Parameter.PRO_CHARACTER, 3, 0);
    custTT.SetFieldMetaData(5, "CreditLimit", 0, Parameter.PRO_DECIMAL, 4, 0);

    return custTT;
}