Obsolete Method?

Good morning,
I am working on a function in Epicor, and after saving and promoting it I got this error. The function makes GET requests to a third-party API. See code below error. Do I have to worry about this error?

GetDeptHrs.cs(122,13): warning CS0618: ‘RestClient.ExecuteAsync(IRestRequest, Action<IRestResponse, RestRequestAsyncHandle>)’ is obsolete: ‘This method will be removed soon in favour of the proper async call’

Function GetDeptHrs(deptKey in, myDate in, deptHrs out)

try
{
    // Base URL for the API
    var URL = "URLSTRING";

    // Initialize RestClient
    var client = new RestClient(URL);

    // Parse myDate to match the expected format for the API call
    if (!DateTime.TryParseExact(myDate.ToString(), "M/d/yyyy h:mm:ss tt", null, System.Globalization.DateTimeStyles.None, out DateTime dateTimeValue))
    {
        // Debug message for invalid date format
        myDebugMsg += "[ERROR] Invalid date format";
        return; // Exit the try block as date parsing failed
    }
    string formattedDate = dateTimeValue.ToString("yyyy-MM-dd");

    // Debug message for formatted date
    myDebugMsg += "Formatted Date: " + formattedDate + " | ";

    // Construct the API request URL
    var myRequest = "webapi/timecards/level/" + deptKey + "/payrolldata/" + formattedDate;
    myDebugMsg += myRequest;
    
    // Create a RestRequest with the constructed URL and GET method
    var request = new RestRequest(myRequest, Method.GET);

    // Add authorization header
    request.AddHeader("Authorization", "Basic AUTHSTRING");

    // Execute the request
    IRestResponse myIResponse = client.Execute(request);

    // Check if request was successful
    if (myIResponse.StatusCode != System.Net.HttpStatusCode.OK)
    {
        // Debug message for failed API request
        myDebugMsg += "[ERROR] API request failed: " + myIResponse.ErrorMessage + " | ";
        return; // Exit the try block as API request failed
    }

    // Extract response content
    string responseData = myIResponse.Content;

    // Debug message for successful API response
    myDebugMsg += "API Response: " + responseData + " | ";

    // Parse the response data into a JSON array
    JArray jsonData;
    try
    {
        jsonData = JArray.Parse(responseData);
    }
    catch (Newtonsoft.Json.JsonReaderException ex)
    {
        // Debug message for JSON parsing error
        myDebugMsg += "[ERROR] JSON parsing error: " + ex.Message + " | ";
        return; // Exit the try block as JSON parsing failed
    }

    // Calculate the total hours for selected PayTypeIDs
    int totalMinutes = 0;

    List<string> excludedPayTypeIDs = new List<string> { "JURY", "HOL", "BER", "SICK/VACA", "S1A HOL", "S2A HOL", "S1B HOL", "S2B HOL" };

    int requestsCompleted = 0;
    int requestsTotal = 0;

    foreach (JObject record in jsonData)
    {
        // Extract report date and hours
        string reportDate = DateTime.Parse(((string)record["ReportDate"]).Split('T')[0]).ToString("yyyy-MM-dd");
        if (reportDate == formattedDate && !excludedPayTypeIDs.Contains(record["PayTypeId"].ToString()))
        {
            requestsTotal++;

            // Sending employee status request
            var employeeKey = record["EmployeeKey"].ToString();
            var employeeRequest = new RestRequest("webapi/2/employees/" + employeeKey, Method.GET);
            employeeRequest.AddHeader("Authorization", "Basic AUTHSTRING");

            client.ExecuteAsync(employeeRequest, (response, handle) =>
            {
                requestsCompleted++;
                if (response.ErrorException != null)
                {
                    Console.WriteLine(response.ErrorException);
                    return;
                }

                var employeeData = JObject.Parse(response.Content);
                if (employeeData["EmployeeStatus"]["Description"].ToString() == "Active")
                {
                    totalMinutes += Convert.ToInt32(record["Minutes"]);
                }

                if (requestsCompleted == requestsTotal)
                {
                       deptHrs = ((decimal)totalMinutes / 60);  
                }
            });
        }
    }
}
catch (Exception ex)
{
    // Debug message for other exceptions
    myDebugMsg += "[ERROR] Exception: " + ex.Message + " | ";
}

The basic idea of this function is to pull the total hours from the department. It only gets hours for the employee if they are “active” and it only takes working hours, not vacation, sick, holiday, etc.

When I convert the Async request to a regular request to get rid of that warning, the function seems to be returning 0 or more likely failing in the background. I can’t tell. This is the code I used when I converted from Async.

try
{
    // Base URL for the API
    var URL = myURL;

    // Initialize RestClient
    var client = new RestClient(URL);

    // Parse myDate to match the expected format for the API call
    if (!DateTime.TryParseExact(myDate.ToString(), "M/d/yyyy h:mm:ss tt", null, System.Globalization.DateTimeStyles.None, out DateTime dateTimeValue))
    {
        // Debug message for invalid date format
        myDebugMsg += "[ERROR] Invalid date format";
        return; // Exit the try block as date parsing failed
    }
    string formattedDate = dateTimeValue.ToString("yyyy-MM-dd");

    // Debug message for formatted date
    myDebugMsg += "Formatted Date: " + formattedDate + " | ";

    // Construct the API request URL
    var myRequest = "webapi/timecards/level/" + deptKey + "/payrolldata/" + formattedDate;
    myDebugMsg += myRequest;

    // Create a RestRequest with the constructed URL and GET method
    var request = new RestRequest(myRequest, Method.GET);

    // Add authorization header
    request.AddHeader("Authorization", "Basic");

    // Execute the request
    IRestResponse myIResponse = client.Execute(request);

    // Check if request was successful
    if (myIResponse.StatusCode != System.Net.HttpStatusCode.OK)
    {
        // Debug message for failed API request
        myDebugMsg += "[ERROR] API request failed: " + myIResponse.ErrorMessage + " | ";
        return; // Exit the try block as API request failed
    }

    // Extract response content
    string responseData = myIResponse.Content;

    // Debug message for successful API response
    myDebugMsg += "API Response: " + responseData + " | ";

    // Parse the response data into a JSON array
    JArray jsonData;
    try
    {
        jsonData = JArray.Parse(responseData);
    }
    catch (Newtonsoft.Json.JsonReaderException ex)
    {
        // Debug message for JSON parsing error
        myDebugMsg += "[ERROR] JSON parsing error: " + ex.Message + " | ";
        return; // Exit the try block as JSON parsing failed
    }

    // Calculate the total hours for selected PayTypeIDs
    int totalMinutes = 0;

    List<string> excludedPayTypeIDs = new List<string> { "JURY", "HOL", "BER", "SICK/VACA", "S1A HOL", "S2A HOL", "S1B HOL", "S2B HOL" };

    int requestsTotal = 0;

    foreach (JObject record in jsonData)
    {
        // Extract report date and hours
        string reportDate = DateTime.Parse(((string)record["ReportDate"]).Split('T')[0]).ToString("yyyy-MM-dd");
        if (reportDate == formattedDate && !excludedPayTypeIDs.Contains(record["PayTypeId"].ToString()))
        {
            requestsTotal++;

            // Sending employee status request
            var employeeKey = record["EmployeeKey"].ToString();
            var employeeRequest = new RestRequest("webapi/2/employees/" + employeeKey, Method.GET);
            employeeRequest.AddHeader("Authorization", "Basic");

            // Execute the request synchronously
            IRestResponse response = client.Execute(employeeRequest);
            if (response.ErrorException != null)
            {
                // Handle error properly
                myDebugMsg += "[ERROR] Exception during employee request: " + response.ErrorMessage + " | ";
                continue;
            }
      // Check if request was successful
      if (response.StatusCode != System.Net.HttpStatusCode.OK)
      {
        // Debug message for failed API request
        myDebugMsg += "[ERROR] API request failed: " + response.ErrorMessage + " | ";
        return; // Exit the try block as API request failed
      }
              // Parse the response data into a JSON array
              JArray employeeDataArray;
              try
              {
                  employeeDataArray = JArray.Parse(response.Content);
              }
              catch (Newtonsoft.Json.JsonReaderException ex)
              {
                  // Debug message for JSON parsing error
                  myDebugMsg += "[ERROR] JSON parsing error: " + ex.Message + " | ";
                  return; // Exit the try block as JSON parsing failed
              }

            if (employeeDataArray["EmployeeStatus"]["Description"].ToString() == "Active")
            {
                totalMinutes += Convert.ToInt32(record["Minutes"]);
            }
        }
    }

    // Avoid division by zero
    if (requestsTotal != 0)
    {
        deptHrs = ((decimal)totalMinutes / 60);
    }
    else
    {
        myDebugMsg += "[ERROR] Division by zero";
    }
}
catch (Exception ex)
{
    // Debug message for other exceptions
    myDebugMsg += "[ERROR] Exception: " + ex.Message + " | ";
}

I appreciate any advice you all have to offer. Thanks for your time!
Nate

Based on the warning message, I would ignore it as long as it’s working. Actually that’s my go-to for all warnings. This one looks like something a new dev put in while angry at legacy code.

1 Like

If you’re just playing around and testing I would say that’s OK to ignore. But if you plan to use this in a live process then I would try and address it. I would paste that code into an AI and ask. For example, Blackbox AI says the below would be the correct answer. It may sound silly but I found in a lot of cases helps to identify the missing pieces.

    foreach (JObject record in jsonData)
    {
        // Extract report date and hours
        string reportDate = DateTime.Parse(((string)record["ReportDate"]).Split('T')[0]).ToString("yyyy-MM-dd");
        if (reportDate == formattedDate &&!excludedPayTypeIDs.Contains(record["PayTypeId"].ToString()))
        {
            requestsTotal++;

            // Sending employee status request
            var employeeKey = record["EmployeeKey"].ToString();
            var employeeRequest = new RestRequest("webapi/2/employees/" + employeeKey, Method.GET);
            employeeRequest.AddHeader("Authorization", "Basic AUTHSTRING");

            // Execute the request asynchronously
            IRestResponse employeeResponse = await client.ExecuteAsync(employeeRequest);

            if (employeeResponse.ErrorException!= null)
            {
                Console.WriteLine(employeeResponse.ErrorException);
                return;
            }

            var employeeData = JObject.Parse(employeeResponse.Content);
            if (employeeData["EmployeeStatus"]["Description"].ToString() == "Active")
            {
                totalMinutes += Convert.ToInt32(record["Minutes"]);
            }

            requestsCompleted++;

            if (requestsCompleted == requestsTotal)
            {
                deptHrs = ((decimal)totalMinutes / 60);
            }
        }
    }

LE - pasted the wrong code

1 Like

This is the path I was heading down. While GPT can help a lot with syntax, it doesn’t always know the best way. I am afraid it is leading me around in circles. The error message:

The ‘await’ operator can only be used within an async method. Consider marking this method with the ‘async’ modifier and changing its return type to ‘Task’.

Lead me to try using Func for the first time. Am still not getting anywhere with it due to the way that GPT is building the func. Clearly, I still don’t understand Func, and I am trying to use it in a questionable way.
This code looks pretty good from GPT, but member declaration is not allowed inside the code block.

// Define a method to asynchronously execute the employee request
async Task<IRestResponse> ExecuteEmployeeRequestAsync(RestClient client, RestRequest request)
{
    return await client.ExecuteAsync(request);
}

// Define a delegate representing the asynchronous method to execute the employee request
Func<RestClient, RestRequest, Task<IRestResponse>> executeEmployeeRequestAsyncDelegate = ExecuteEmployeeRequestAsync;

try
{
    // Base URL for the API
    var URL = myURL;

    // Initialize RestClient
    var client = new RestClient(URL);

    // Parse myDate to match the expected format for the API call
    if (!DateTime.TryParseExact(myDate.ToString(), "M/d/yyyy h:mm:ss tt", null, System.Globalization.DateTimeStyles.None, out DateTime dateTimeValue))
    {
        // Debug message for invalid date format
        myDebugMsg += "[ERROR] Invalid date format";
        return; // Exit the try block as date parsing failed
    }
    string formattedDate = dateTimeValue.ToString("yyyy-MM-dd");

    // Debug message for formatted date
    myDebugMsg += "Formatted Date: " + formattedDate + " | ";

    // Construct the API request URL
    var myRequest = "webapi/timecards/level/" + deptKey + "/payrolldata/" + formattedDate;
    myDebugMsg += myRequest;

    // Create a RestRequest with the constructed URL and GET method
    var request = new RestRequest(myRequest, Method.GET);

    // Add authorization header
    request.AddHeader("Authorization", "Basic " + myKey);

    // Execute the request
    IRestResponse myIResponse = client.Execute(request);

    // Check if request was successful
    if (myIResponse.StatusCode != System.Net.HttpStatusCode.OK)
    {
        // Debug message for failed API request
        myDebugMsg += "[ERROR] API request failed: " + myIResponse.ErrorMessage + " | ";
        return; // Exit the try block as API request failed
    }

    // Extract response content
    string responseData = myIResponse.Content;

    // Debug message for successful API response
    myDebugMsg += "API Response: " + responseData + " | ";

    // Parse the response data into a JSON array
    JArray jsonData;
    try
    {
        jsonData = JArray.Parse(responseData);
    }
    catch (Newtonsoft.Json.JsonReaderException ex)
    {
        // Debug message for JSON parsing error
        myDebugMsg += "[ERROR] JSON parsing error: " + ex.Message + " | ";
        return; // Exit the try block as JSON parsing failed
    }

    // Calculate the total hours for selected PayTypeIDs
    int totalMinutes = 0;

    List<string> excludedPayTypeIDs = new List<string> { "JURY", "HOL", "BER", "SICK/VACA", "S1A HOL", "S2A HOL", "S1B HOL", "S2B HOL" };

    int requestsTotal = 0;
    int requestsCompleted = 0;
    foreach (JObject record in jsonData)
    {
        // Extract report date and hours
        string reportDate = DateTime.Parse(((string)record["ReportDate"]).Split('T')[0]).ToString("yyyy-MM-dd");
        if (reportDate == formattedDate && !excludedPayTypeIDs.Contains(record["PayTypeId"].ToString()))
        {
            requestsTotal++;

            // Sending employee status request
            var employeeKey = record["EmployeeKey"].ToString();
            var employeeRequest = new RestRequest("webapi/2/employees/" + employeeKey, Method.GET);
            employeeRequest.AddHeader("Authorization", "Basic " + myKey);

            // Execute the request asynchronously using the delegate
            var employeeResponse = await executeEmployeeRequestAsyncDelegate(client, employeeRequest);

            if (employeeResponse.ErrorException != null)
            {
                Console.WriteLine(employeeResponse.ErrorException);
                return;
            }

            var employeeData = JObject.Parse(employeeResponse.Content);
            if (employeeData["EmployeeStatus"]["Description"].ToString() == "Active")
            {
                totalMinutes += Convert.ToInt32(record["Minutes"]);
            }

            requestsCompleted++;

            if (requestsCompleted == requestsTotal)
            {
                if (requestsTotal != 0)
                {
                    deptHrs = ((decimal)totalMinutes / 60);
                }
                else
                {
                    myDebugMsg += "[ERROR] Division by zero";
                    deptHrs = 0;
                }
            }
        }
    }
}
catch (Exception ex)
{
    // Debug message for other exceptions
    myDebugMsg += "[ERROR] Exception: " + ex.Message + " | ";
}

I think the problem is around the use of Task> in the delegate, but I have no idea…

I’m not sure if you need to mess around with the await operator. I would start simple - below are parts of the code for a function that runs a BAQ and does REST calls for each row.

// LOOP ALL RESULTS IN BAQ
for (int i=0; i<dsQryRez.Tables[0].Rows.Count; i++)
{
    // create new rest client
    client = new RestClient(rpURL);
    client.Timeout = -1;
    request = new RestRequest(Method.POST); 
    request.AddHeader("Content-Type", "application/json");
    request.AddHeader("Authorization", rpToken);
    
    // create objTCall JSON here...

    // serialize JSON object 
    string sbdy = Newtonsoft.Json.JsonConvert.SerializeObject(objTCall); 
    
    // EXECUTE CALL
    request.AddParameter("application/json", sbdy,  ParameterType.RequestBody);
    IRestResponse response = client.Execute(request);
    int tgresponsecode = Convert.ToInt32(response.StatusCode);
    string tgresponsecontent = response.Content.ToString();
    
    if (tgresponsecode==200)
    {
      // call OK

    }
    else
    {
      // Call failed
    }
    
 
// END LOOP
}

1 Like
  1. If you are at all confused, don’t use ChatGPT.
  2. If you decide to anyway, and you don’t understand what bs ChatGPT is trying to spit out, then see rule 1.
  3. Don’t use ChatGPT.

Switch to the synchronous method. You are already in a synchronous function, so what is the point?

Finally, if you just want the error to disappear, put this above the method:

#pragma warning disable 0618

4 Likes

Star Trek Borg GIF

They always said that, but they always got their cubes blown up in the end.

1 Like

ChatGPT is the equivalent of the predictive text on your phone, just with a few orders of magnitude more information to rely on.

Impressive? sure

Useful? occasionally

Smart? Intuitive? Understanding?
Nope

1 Like

I mean seriously, do you understand what I’m ducking saying?

1 Like

Duck yeah brother. The terrible truth is GPT is still faster at spitting out a 90% outline that usually needs only minor edits. Syntax is half the battle. It certainly doesn’t know the best way. It really is just doing what I was before GPT. I’m a hack for sure… I would find related code and paste it into my project. Then spend the next few days debugging my mistakes. Except that GPT is “smart” enough to validate the syntax and include my context. It might not save time for a pro like you, but it saves hacks like me lots of time and frustration. Missed that closed parenthesis? GPT didn’t. Missed that semicolon? Not GPT. Didn’t declare that variable in the right scope? GPT noticed. How is that not useful, even as a sanity check?

I am going to avoid async calls as suggested. I don’t think it was the right path anyway.

Having said that, I have to make multi-step API calls to return the data I need. For example, I have to first call the API to pull my employee IDs, then use those IDs to call the API for the hours by ID. There are actually a few more steps than this. Trying to figure out the right order to make the calls in Epicor has been tricky.

Do you think it is better to isolate each API call to its own function, or setup all the API calls nested into a single function?

I try not to over-ducking-engineer sheet so I wonder if I could do some of that in a BAQ? BAQs are powerful but the programming ego in me wants to code. :person_shrugging: But if I can do three calls in one query, I feel like a forking genius.

Yes.

I mean, it depends. I prefer to break out function/APIs to make them easy to test - even if they get packaged into one API later. If I do want to add functionality down the road, it’s easier to piece together pieces than to pull them apart and redo the logic from the single API. YMMV.

1 Like

Yes and I agree. But if you’re looking for a specific thing, it can help a lot. For example, I had a function in Azure using REST version 80 and something and I had to upgrade it to latest version 130. After the upgrade, the code didn’t work. Guess what I did to upgrade it? Copilot! It was indeed the paid version but it gave me 95% of what I needed. So I wouldn’t say don’t use it at all.

1 Like

I use chatGPT, I just don’t use ChatGPT’s code

There’s always a but.

Sometimes an opinion is worth what you paid for it…

I was mostly being snarky anyway :rofl: