cancel
Showing results for 
Search instead for 
Did you mean: 

Generic Exception-handling wrapper for Unity Scripts?

Alex_French
Elite Collaborator
Elite Collaborator

Over several years, based largely on seeing code written by other developers and classes/discussion at TechQuest, I've built up a pretty standard set of exception handling practices for almost all Unity Scripts (mainly standard Workflow scripts).  It includes:


1) Do all actual work in a try-catch block

2) Set the Diagnostics level based on a Configuration Item value, and log the Script's beginning and end to the Diagnostics Console.

3) On an Exception, write detailed information to the Diagnostics Console and set detail (at least the script name and a line number, maybe an abbreviated stack trace too) to a Property that can be used from Workflow.


But that led to A LOT of boiler plate that clutters up a casual reading of the script.  usually the main script entry point would have ~25 lines of code, with an actual method call in the middle of it, to a method that implemented all business logic.

What I've recently switched to doing is using a Library with all that exception handling in a method that accepts a business logic method as an arguement.

Here's the signature of that method:



    public delegate void WorkflowScriptDelegate(Hyland.Unity.Application app, Hyland.Unity.WorkflowEventArgs args);
        
    public static void WorkflowScriptExecuteWithExceptionHandling(Hyland.Unity.Application app, Hyland.Unity.WorkflowEventArgs args, string scriptName, WorkflowScriptDelegate myDelegate)
    

Now any given individual Unity Script references that Library and looks something like this:


    public void OnWorkflowScriptExecute(Hyland.Unity.Application app, Hyland.Unity.WorkflowEventArgs args)
    {
        LIBExceptionsGeneral.WorkflowScriptExecuteWithExceptionHandling(app, args, SCRIPT_NAME, main);
    }
    
    private main(Hyland.Unity.Application app, Hyland.Unity.WorkflowEventArgs args)
    {
        //All business logic here
        //...
    }
        

That makes for a script that is much easier to grok at a glance, whether you're me or another programmer or an OnBase developer who can read a little C# but really, really doesn't want to look at all the previous boilerplate at a glance.

Or sometimes all the business logic moves into a Library, and so the actual entry point script becomes extremely simple:


    
    public void OnWorkflowScriptExecute(Hyland.Unity.Application app, Hyland.Unity.WorkflowEventArgs args)
    {
        LIBExceptionsGeneral.WorkflowScriptExecuteWithExceptionHandling(app, args, SCRIPT_NAME, LIBBusinessLogic.DoThisThing);
    }

At that point I might have several Scripts that are called for different parts of related operations (CreateBatch, Add to Batch, Update Batch, Remove From Batch)- but each is just an entry point into a library that contains all the related business logic in one place, and doesn't need to do any of that boiler plate Exception handling (though of course it may want to do more specific Exception handling, and is still generally responsible for lots of checks to avoid Exceptions to start with).

One thing I haven't done yet is used the techniques discussed in this Community Post to information at runtime about the executing Script:

    https://www.onbase.com/community/technical_communities/onbase_apis/f/unity-apis/26744/can-we-access-...


I'm still maintaining the script's name by hand and passing it into my "ExecuteWithExceptionHandling" function, but using options mentioned there to programmatically identify the calling script's name and version will be a nice improvement.
    
Does anyone else user similar techniques?  Or have other related ideas to share that help avoid boilerplate code and manual repetitive coding of things you do a lot in Unity Scripts?

2 ACCEPTED ANSWERS

Seth_Yantiss
Star Collaborator
Star Collaborator

This is really good stuff!!! We follow a lot of what you wrote as well.

One thing I would add, NEVER use the Run Unity Script "Action", always use the "Rule". I'm not really sure why the action is even there.

The "True/False" decision tree after the execution of the script can be used to send notifications on the status of the execution, or to define error handling rules. It can also be used as a means of executing next steps.

Cheers!

View answer in original post

Nevin_Steindam
Star Contributor
Star Contributor

These practices look good. I want to point out that as of OnBase 16, you no longer need to set the diagnostics level through a Configuration Item. Now there is a built-in setting that you can use to set each script's logging level individually. (Manage Unity Projects -> Select the Desired Script -> Manage Diagnostics.) This value determines the log level when the script starts, so if you continue to change it in your code, that will override the built-in setting.

View answer in original post

4 REPLIES 4

Seth_Yantiss
Star Collaborator
Star Collaborator

This is really good stuff!!! We follow a lot of what you wrote as well.

One thing I would add, NEVER use the Run Unity Script "Action", always use the "Rule". I'm not really sure why the action is even there.

The "True/False" decision tree after the execution of the script can be used to send notifications on the status of the execution, or to define error handling rules. It can also be used as a means of executing next steps.

Cheers!

Nevin_Steindam
Star Contributor
Star Contributor

These practices look good. I want to point out that as of OnBase 16, you no longer need to set the diagnostics level through a Configuration Item. Now there is a built-in setting that you can use to set each script's logging level individually. (Manage Unity Projects -> Select the Desired Script -> Manage Diagnostics.) This value determines the log level when the script starts, so if you continue to change it in your code, that will override the built-in setting.

Alex_French
Elite Collaborator
Elite Collaborator

@Seth: We have gradually settled on a relatively standard set of things to do in Workflow when a script returns False- basically a little matrix of "is this action user facing" and "should the thing stay where it is on failure" leads to either "Display Message Box" or "Create Note" with some Property contents, and either the Document just stays where it is and execution stops or it moves to an Exception queue.

In rare cases we might have to think harder about partially complete operations and what's going on with related documents, but even then the answer is probably "report information about how messed up things are", not "back out of this operation".

I agree 99% with "ALWAYS use the Run Unity Script Rule". The one place that I've just recently started violating that and using the Action is when calling a script "GetConfigurationItem".

That one should be easy to make pretty darn air-tight- at least as air-tight as ever using Properties in Workflow, so right now I feel okay about using that script in the Action. If felt the trade off was worth it fro simplicity (though it still requires at least two more lines of Workflow- one to set "propConfigItemName" before the script and one to get "propCongifItemValue" and do something with it). Ask me in three years whether I think that tradeoff was a good choice for slightly simpler Workflow, or if I've switched to from 99% back to 100%.

Alex_French
Elite Collaborator
Elite Collaborator
@Nevin: That does seem like a nice feature to have. It's too bad it couldn't be setup to work so that the per-script setting always overrides a setting code- but I'm sure if it worked that way I'd come up with some reason that I wished it worked the way it does.

Thanks for both the content of the TechQuest class a few years ago and the chat at TechQuest in November that influenced a lot of how I do things.
Getting started

Find what you came for

We want to make your experience in Hyland Connect as valuable as possible, so we put together some helpful links.