Invalid Dataset Error During Function API Call

I’m trying to generate a BAQ report via function call. I’ve followed the trace and seem to be getting hung up on the last method call (Ice.RPT.BAQReportSvc.TransformAndSubmit). I’ve used the “Ice.BAQReport.GetNewBAQReportParam” method to return a tableset. I’ve then used C# to convert the tableset to a dataset to serve as the input param for the TransformAndSubmit method. I’ve verified that my dataset matches exactly to the payload from the trace for this method. When I attempt to make the function call through the API, I continue to get an Invalid Dataset error.

What’s frustrating is that if I copy the dataset output from the API response and use it as an input parameter for the TransformAndSubmit method via Swagger API, I get a status 200 and my report generates without issue. This seems to indicate to me that the ds is complete and adequate?

I’ve tried a number of different strategies, including serializing the ds to json and passing that in as a parameter, initializing the ds as a new object in the C# widget (even though it’s already defined in my function signature), and passing in the tableset as an object parameter, nothing seems to work. Below is my code, @klincecum I’ve seen some similar threads where you’ve offered some things to try. Anything you can think of that might get me over this last hurdle?

try
{
    using (DataSet dataSet = new DataSet("ds"))
    {
        // Explicitly define the type of the tables to process
        var tablesToProcess = new List<Tuple<dynamic, string>>()
        {
            new Tuple<dynamic, string>(baqRptTS.BAQReportParam, "BAQReportParam"),
            new Tuple<dynamic, string>(baqRptTS.ReportStyle, "ReportStyle"),
            //new Tuple<dynamic, string>(baqRptTS.ExtensionTables, "extensionTables")
        };
        
        //Try adding a blank table for ExtensionsTable to match trace
         dataSet.Tables.Add(new DataTable("extensionTables"));


        foreach (var tableInfo in tablesToProcess)
        {
            var table = tableInfo.Item1;
            var tableName = tableInfo.Item2;

            if (table != null)
            {
                using (DataTable dataTable = new DataTable(tableName))
                {
                    // Step 1: Add columns to the new DataTable
                    foreach (var column in table.Columns)
                    {
                        Type columnType = column.DataType;

                        // Check if the column type is nullable
                        if (columnType.IsGenericType && columnType.GetGenericTypeDefinition() == typeof(Nullable<>))
                        {
                            // If nullable, use the underlying type and allow nulls
                            columnType = Nullable.GetUnderlyingType(columnType);
                            dataTable.Columns.Add(column.ColumnName, columnType).AllowDBNull = true;
                        }
                        else
                        {
                            dataTable.Columns.Add(column.ColumnName, columnType);
                        }
                        
                    }

                    // Step 2: Copy each row from the source table to the new DataTable
                    foreach (var sourceRow in table)
                    {
                        DataRow newRow = dataTable.NewRow();

                        // Copy each column's value
                        foreach (DataColumn column in dataTable.Columns)
                        {
                            object value = sourceRow[column.ColumnName];
                            newRow[column.ColumnName] = value ?? DBNull.Value;
                        }

                        dataTable.Rows.Add(newRow);
                    }
                    
                    //Testing to add "SSRSRender" column to Report Style table
                    bool checkForColumn1 = dataTable.Columns.Contains("SSRSRenderFormat");
                    
                    if (checkForColumn1 == false)
                    {
                        dataTable.Columns.Add("SSRSRenderFormat", typeof(string));
                        foreach (DataRow row in dataTable.Rows)
                        {
                            // Set the value for each row in the "SSRSRenderFormat" column
                            row["SSRSRenderFormat"] = "PDF";
                        }
                    }

                    // Step 3: Add the new DataTable to the DataSet
                    dataSet.Tables.Add(dataTable);
                    
              
                    
                }
            }
        }

        //ds = new DataSet();

        ds = dataSet;
        
        
        //Try calling transform and submit method from here
        CallService<Ice.Contracts.BAQReportSvcContract>(svc =>
            {
                svc.TransformAndSubmit(ds, "PRINT", 0, 0, "Ice.UIRpt.TEDMtlTag" );
            });
        
    }
}
catch (Exception ex)
{
    exceptionMsg = "An unexpected error occurred: " + ex.Message + ex.StackTrace;
}
1 Like

I’m working on some write-only regex at the moment :rofl:

I’ll see if I can poke it later.

1 Like

When the kids were constipated, their faces made irregular expressions.

I better get a poop emoji @klincecum

2 Likes

I’ve found a real world use for ChatGPT → writing regular expressions! Thanks @josecgomez

1 Like

It is worth its weight in gold just for that.

2 Likes

Bing even makes jokes when I tell it to write regex once again :slight_smile:

3 Likes

Also I want to find Stephen Kleene (or his kids since he died) and ask him why in the hell did he have to make it so frigging obscure, hard to use and impossible to remember.

Anytime I can avoid Stack Overflow … It’s worth it.

#Toxic lol → even for us old folks

2 Likes

Sorry @ben.perkins , I will poke at it later, I promise!

:dumpster_fire:

2 Likes

Grow Do Something GIF by AionCommunity

1 Like

Decomp of the source shows you must have at least one ds.BAQReportParam. And the first param is passed in to an internal call. (I presume this is report related stuff, agent, sched, etc)

1 Like

Got it, it’s bs really…

I gotta get ready for work, so I’ll post up later, with how to use the traditional SubmitToAgent as well as the wierdness discovered with TransformAndSubmit (with example for use as well).

Awesome, thanks Kevin. Look forward to seeing what you discovered!

Here’s a clue.

dance dancing GIF

1 Like

Thanks Chris. My ds does have one row in the BAQReportParam table which contains, among other things, the report ID, option criteria, etc. When I construct my dataset, I am adding a blank extensionsTable as the first table, in an effort to match the trace object, not sure if that’s throwing things off or not…

Some of y’all will laugh, some will sigh a little when I show you what it is.

I think Epicor has been having swap your backend and frontend programmers days.

I’ll be at work in a bit.

When he did it it was normal. I rememeber Perl programming, also almost write-only stuff.

3 Likes

A tale of two DataSets… or is it?

When is a DataSet not a DataSet ?

It looked like a duck, quacked like a duck, but alas, it was not a duck.

Well I wish I had just checked, as this would have been a clue to speed this along…
Here is the function signature for TransformAndSubmit

BAQReportSvcContract.TransformAndSubmit(object, string, long, int, string)

That first parameter is of type object. What kind of object? You’d be forgiven for thinking it’s a DataSet, since for all practical purposes, it is.

Well it’s not.

It’s pretty much a JObject / JToken. Pretty much the Newtonsoft representation of a DataSet, if you deserialized JSON directly without a type.

Here is the code that works with TransformAndSubmit

//TransformAndSubmit Example

//Send json serialized object to the system monitor through the error report mechanism..
//This will terminate the function btw
Action<object> ThrowJson = (o) =>
{
    throw new BLException(JsonConvert.SerializeObject(o));
};

string reportID = "smwh";
int reportStyleNum = 1;

CallService<Ice.Contracts.BAQReportSvcContract>(baqReportSvc =>
{
    Ice.Tablesets.BAQReportTableset baqReportTS = baqReportSvc.GetNewParametersForReportId(reportID);
    
    //ThrowJson(baqReportTS); //Debug
    
    var baqParams = baqReportTS.BAQReportParam.FirstOrDefault();

    baqParams.BAQID            = "smwh";    
    baqParams.UserID           = Session.UserID;
    baqParams.ReportID         = reportID; //Not needed, call to GetNewParametersForReportId takes care of it
    baqParams.AutoAction       = "SSRSPREVIEW";
    baqParams.WorkstationID    = $"web_{Session.UserID}";
    //baqParams.WorkstationID  = Session.TaskClientID; //You can use this too
    baqParams.ReportStyleNum   = reportStyleNum;
    baqParams.AttachmentType   = "PDF";
    baqParams.SSRSRenderFormat = "PDF";
    //baqParams.RowMod         = "A"; //Not needed, call to GetNewParametersForReportId takes care of it
    
    //ThrowJson(baqReportTS); //Debug

    //Does NOT work!
    //baqReportSvc.TransformAndSubmit(baqReportTS, "", 0, 0, $"Ice.UIRpt.{reportID}");

    //Does NOT work!
    //DataSet ds = Ice.DatasetAdapter.ConvertToGenericDataset(baqReportTS, "", null, true);
    //baqReportSvc.TransformAndSubmit(ds, "", 0, 0, $"Ice.UIRpt.{reportID}");

    //Works
    //DataSet ds = Ice.DatasetAdapter.ConvertToGenericDataset(baqReportTS, "", null, true);
    //string json1 = JsonConvert.SerializeObject(ds);
    //baqReportSvc.TransformAndSubmit(JsonConvert.DeserializeObject(json1), "", 0, 0, $"Ice.UIRpt.{reportID}");

    //Works
    //string json2 = JsonConvert.SerializeObject(baqReportTS);
    //baqReportSvc.TransformAndSubmit(JsonConvert.DeserializeObject(json2), "", 0, 0, $"Ice.UIRpt.{reportID}");

    //Works
    string json3 = JsonConvert.SerializeObject(baqReportTS);
    baqReportSvc.TransformAndSubmit(JToken.Parse(json3), "", 0, 0, $"Ice.UIRpt.{reportID}");

    //Works
    //string json4 = JsonConvert.SerializeObject(baqReportTS);
    //baqReportSvc.TransformAndSubmit(JsonConvert.DeserializeObject<dynamic>(json4), "", 0, 0, $"Ice.UIRpt.{reportID}");


    //Transform and submit is not taking a DataSet, it wants and object that "looks" and "feels" like a DataSet (It's a damn dataset lol!)
    //Function Signature -> BAQReportSvcContract.TransformAndSubmit(object, string, long, int, string)'
    //Object is "ds", but it is not a DataSet. This wants a JToken or something similar 
 
});

And as promised, the SubmitToAgent Example as well →

//SubmitToAgent Example

//Send json serialized object to the system monitor through the error report mechanism..
//This will terminate the function btw
Action<object> ThrowJson = (o) =>
{
    throw new BLException(JsonConvert.SerializeObject(o));
};


string reportID = "smwh";
int reportStyleNum = 1;

CallService<Ice.Contracts.BAQReportSvcContract>(baqReportSvc =>
{
    Ice.Tablesets.BAQReportTableset baqReportTS = baqReportSvc.GetNewParametersForReportId(reportID);
    
    //ThrowJson(baqReportTS); //Debug
    
    var baqParams = baqReportTS.BAQReportParam.FirstOrDefault();

    baqParams.BAQID            = "smwh";
    baqParams.UserID           = Session.UserID;
    baqParams.ReportID         = reportID; //Not needed, call to GetNewParametersForReportId takes care of it
    baqParams.AutoAction       = "SSRSPREVIEW";
    baqParams.WorkstationID    = $"web_{Session.UserID}";
    //baqParams.WorkstationID  = Session.TaskClientID; //You can use this too
    baqParams.ReportStyleNum   = reportStyleNum;
    baqParams.AttachmentType   = "PDF";
    baqParams.SSRSRenderFormat = "PDF";
    //baqParams.RowMod         = "A"; //Not needed, call to GetNewParametersForReportId takes care of it



    //Begin Write XML----------------------------------------------------------------------------------------------->
    var dynamicReportTableset = new Ice.Tablesets.DynamicReportTableset();
   
    CallService<Ice.Contracts.DynamicReportSvcContract>(dynamicCriteriaSvc=>
    {
       dynamicReportTableset = dynamicCriteriaSvc.GetByID(reportID);
    });
    
    var dynamicReportDataSet = Ice.DatasetAdapter.ConvertToGenericDataset(dynamicReportTableset, "", null, true);

    StringWriter writer = new StringWriter();
    dynamicReportDataSet.WriteXml(writer);

    baqParams.Filter1 = writer.ToString();
    //-------------------------------------------------------------------------------------------------End Write XML>
    

    //ThrowJson(baqReportTS); //Debug
    
    baqReportSvc.SubmitToAgent(baqReportTS, "", 0, 0, $"Ice.UIRpt.{reportID}");

});

Files →
PrintBAQReportExample1.efxb (6.3 KB)
PrintBAQReportExample1.efxj.txt (6.8 KB) ← Remove .txt

2 Likes

The Next Generation No Reply GIF by Star Trek

1 Like

Awesome, thank you Kevin! I’m getting a compile error on JToken (doesn’t exist in current context). I’ve got a reference to Newtonsoft.Json.dll in my Reference Assemblies of the function, any ideas?

1 Like