Function Exceptions

Creating my first function(s). I am calling a function from another function. It is very possible that the called function will hit an exception. I am been trying to get the called function to pass back the exception to the calling function (try/catch), store that for now in a variable and continue processing the next record. I have been successful in getting the exception message back to the calling function using callContextBpmData (assigned in catch block) when limiting the process to run only for one record but if I process more than 1 the message never is returned. The second part to this is that both the calling and caller functions are marked as Requires Transaction, I am doing a CallService to perform some BO Methods. What happens is that the process hits the exception and never continues to the next records recording a error in the system monitor. I have not found a way to get around that yet either, to continue when exception has been hit. I keep thinking I may have to do my own pre-checks and not rely on catching the exception and pass control back to the calling function. Is there a way to break out of a function early.

Overall I am trying to put a scheduled Quote Closing process into place by checking to see if a SO was created and also complete any open tasks that may still be on the Quote. It is in completing, really doing the Update method, that it may hit an exception and I want to record that but continue with the next record.

Scott

Not that its the exact solution you are looking for, but i created something similar with a UBAQ and BAQ Export to process quote expiration.

It doesn’t check if a sales order is available. It simply checks if the current task is losable and marks it.

What we’ve done is adopt a pattern where every function returns a Success boolean and a ErrorMessage string, so that wherever it’s called, the consuming code can decide if it wants to check for success and continue or not. That way, you don’t automatically bomb out a whole loop if one record fails. And since we return the error message (from a catch block) that can be fed into the UI, (like a grid if you are using it in a UBAQ or something).

If success comes back true, the error is blank and you move on with your life. Seems to work well.

1 Like

Samsies. Every function returns oSuccess and oMessage. If there are internal https calls I also return oStatus

1 Like

Thanks for the replies, I ended up doing somewhat the same thing, check for the exception in the called function and return the message back to the calling function but I am using callContextBpmData so that I can also get the entire error message back. It sounds like you and @Banderson are using signature response parameters. How are you handling what type of exception it is, or does not matter just that it failed, which in most cases would be fine but in some you need to know what type of exception was hit.

If you do get an exception back Scott, how do you tell it to proceed and not bomb out? The same question to you @Banderson you mentioned that “it can decide if it wants to continue or not…” I always thought if an exception hits, the loop is over, is that not true?

The way I am doing it I am passing back any error message encountered through callContextBpmData.Character02, if that is a empty string no error encounter, if not then what is the error and then proceed with handling that exception in the calling function. But I want to test out the oError, oSuccess pattern @Banderson and @jgiese.wci to see if that works better. That may be more for Widget type functions but I am using Custom Code so I am not sure if that pattern will work in this case.

So in other words the function will continue even if there is an error so you are capturing the error param from a method call in call context and passing it back to check if you should exit the loop?

The called function has a try/catch so in the catch I populate callContext and exit that function and then it depends in the calling function what the exception was and proceed accordingly in that function.

I see, you are doing it in code. I was wondering how to handle this with custom widgets.

Thanks for the explanation :pray:

You put the code in a try catch. If it bombs in the try, then you hit the catch, where you send back the exception and make success false.

this works for both, you return the information both ways.

That depends on what you are doing I guess. I haven’t done anything yet where one step affects the next, and if it did, I probably wouldn’t continue at all regardless of the exception. But that’s really going to be on a case by case basis.

After the discussion about SPAs and API Keys AND my current compulsion with Zero Trust Architecture, I’ve been investigating a different architecture.

The idea is to wrap an Epicor Function in lightweight Azure Function. This is a pure consumption model. No worries about patching servers; it auto-scales, pay only for what you use with a free quota every month. Then put the Azure Function behind Azure API Management.

The benefits:

  • Aligns with Zero Trust Principles (segmentation, identity, assume breach)
  • Works with Single Page Applications
  • Clients can now utilize the standard HTTP Status Codes
  • Uses Active Directory for Identity - including 3rd parties if necessary and Access Management
  • Enables Active Directory Conditional Access for sensitive operations
  • API-Key is secured in a Azure Key Vault or Secret Store and never exposed to the client. Easy key rolling.
  • Rate Limiting
  • IP Filtering
  • CORS protection without modifying Epicor’s Web Config
  • Enable cache responses where reasonable
  • Better logging for your Security Information and Event Management (SIEM)

This should work with SaaS, private cloud, and on prem organizations.

4 Likes

Thanks for the info Mark, I am playing around with some AI stuff right now in azure and will start to make an application soon.

Thinking about function app or power app maybe or pushing the model to an IoT device so everything is done locally, no need to expose anything outside the domain.

Azure is fascinating.

1 Like

@slitzau would you be willing to post the code for the foreach loop that calls your function?

@Banderson I have this function and I am having trouble calling it from custom code widget in a BPM. Do you know what I am doing wrong?

Full disclosure I don’t know what I am doing with this call.

Why you casting your params to tuples?

I have no clue, every example I see on here of people calling functions from C# are using this…

should I just pass the params as is?

Yes :wink:
Tuple types - C# reference | Microsoft Docs

1 Like