Building Streamlined, Traceable and Error Handled Canvas App Functions

Building processes in Canvas App is fast and you can get a lot done very quickly. Actions that, for example, a button control does, can become very complex very quickly, and that means the developer needs to iterate and focus on only making the code work, but also how readable it is, how comments are made, and how errors are handled. I decided to create this blog post to give ideas of what I have learned over the years, and hopefully you will get some ideas to help your development!
In this blog, we will create a basic example of a button action that includes With, Trace, and IfError functions. You can find the code at the end of the post.
Streamline using With function
The With function is useful when a process contains multiple functions using the same data fields or complex calculations. This function enables us to declare input parameters (a custom record) that can be used inside the formula block.
What makes it so useful? Custom records enable us to manage the values in a single location instead of having complex calculations duplicated 3 to 5 times in our code. Sometimes this is a case when we are, for example, using IfError—more on that later.
In the example below, we have a button that collects a user’s inputs. In the With function, we will create a record from the input and hard-coded values. I like to use the _keyName naming convention to easily see in the Formula which values are just for the With function and which are dynamic.

We have created our record and are ready to use the custom values in our formula block of the With function. In this example, the If function checks the number of new employees compared to our hard-coded _maxUserCount. If our comparison is true, a new employee is added to the collection, if not, a notification is displayed to the user.
Hopefully, this simple example gave you ideas of how to utilize the With function in your app development! Remember to check out the documentation: With function – Power Platform | Microsoft Learn.
Track using Trace function
Every action creates a log in the built-in monitoring tool inside the canvas app. That tool is really useful when developing the solution and troubleshooting end-user errors that might be happening. With Trace, you can create custom logs to view during monitoring. Why create custom logs when every action is logged anyway? Traces are very easy to find from the list, and you can create custom values that you want to track and follow where the user is in the process. Combining Trace with IfError is a powerful tool for understanding what is happening inside the process.
Let’s continue our code. We have our With function, and we would like to add Traces to it. Firstly, let’s create another With function inside our If-true branch. The record could be accessed as ThisRecord in the next steps, but we have embedded With functions, which means that we have two default ThisRecord values. We can use an As expression and give the record a custom name. Then, we can use the record in our Collect function and our Trace function.

Now let’s test this. Open Live Monitoring and start recording your steps. Clicking the button executes our Collect and Trace functions. We validate the operations from the monitoring tool, and it seems that our code worked as intended.

We can see that the Collect operation is clearly visible, so why use Trace? The benefit I have found from using Trace is that it is easily filtered from Operations. Your app might generate hundreds or thousands of rows per session, so Trace + custom Result info makes it easier to figure out what part of the app the user has been using and what the results are. You can also add a custom record to your Trace as we did in this example. The Collect operation does not show saved values as seen in the images below.


Check out more in the documentation: Trace function – Power Platform | Microsoft Learn.
Handle errors with IfError function
The IfError function enables us to build apps that do not just raise their hands when an error occurs and leave the end user unaware of the error or just receiving a system error notification, which most of the time does not tell the end user anything. IfError is probably better known as Try-Catch, and it gives us a way to create functions with handled errors. Below, you can find an example of how to utilize IfError.

Let’s break it down! Our example is now wrapped inside the first value (try) block: the IfError function. If our function to add a new user to the collection is successful, then the fallback (catch) block is skipped, and the user is notified that creation was successful. If our function results in an error, then the user is notified, and rest of the code inside the IfError is not executed. Remember that if you have a following IfError, that is executed!
You can create a sequence of functions and fallbacks for each step in your process. If one step fails, then the rest of the functions are not executed. Always think about error handling while developing your solutions! Read more about IfError and other error handling functions: Error, IfError, IsError, and IsBlankOrError functions – Power Platform | Microsoft Learn
Code and other functions to check out
To wrap up, building processes in Canvas App can be both fast and efficient, but it requires careful attention to detail to ensure the code is not only functional but also readable and maintainable. By leveraging functions like With, Trace, and IfError, you can streamline your code, enhance traceability, and handle errors gracefully.
I hope this blog has provided you with valuable insights and practical examples to improve your app development. Remember, the key to successful development is not just writing code that works, but writing code that is clean, understandable, and robust. Happy coding!
Microsoft lists all available Canvas App functions in their Learn page. If you have struggled to find correct functions for your processes, have a look at this list!
With(
// record-block
{
_requestedBy: User().FullName,
_firstName: txt_FirstName.Text,
_lastName: txt_LastName.Text,
_requestTime: Text(
Now(),
"dd.mm.yyyy HH:mm"
),
_maxUserCount: 10
},
// formula-block
IfError(
// try
If(
CountRows(colNewEmployee) <= _maxUserCount,
// add new user to collection
With(
{
'First Name': _firstName,
'Last Name': _lastName,
'Requested By': _requestedBy,
'Request Time': _requestTime
},
Collect(
colNewEmployee,
ThisRecord
);
Trace(
"New user added to collection",
TraceSeverity.Information,
{Value: ThisRecord}
)
),
// notify user that they have reached user limit
Notify(
"You have reached your allowed user limit of " & _maxUserCount & ". Unable to add new user " & _firstName & " " & _lastName,
NotificationType.Warning
)
),
// catch
Notify(
"An error occured while trying to add new user " & _firstName & " " & _lastName & ". Please try again!",
NotificationType.Error
),
// try
Notify(
"New user " & _firstName & " " & _lastName & " successfully created to collection!",
NotificationType.Success
),
// catch
Trace(
"Error happend while notifying end user",
TraceSeverity.Error
)
)
)