Exception Best Practice
Handling exceptions is very crucial in our dynamics projects.
Handling exceptions is an important part of any development effort. Prevention is better then cure. As a developer I always try to prevent errors or exceptions but sometimes there will be exceptions beyond control so we have to handle this type of exceptions correctly.
-
Handling Exceptions in Plug-ins
- For synchronous plug-ins, whether registered in the sandbox or not, the Microsoft Dynamics CRM platform handles exceptions passed back from a plug-in by displaying an error message in a dialog of the web application user interface.
- The exception message for asynchronous plug-ins is written to a System Job (AsyncOperation) record which can be viewed in the System Jobs area of the web application. In Advance Find look for System Jobs entity to get details.
- If your plugin runs infinite loop then restrict the plugin by context.Depth property.
- For synchronous plug-ins, you can optionally display a custom error message in the error dialog of the web application by having your plug-in throw an InvalidPluginExecutionException exception with the custom message string as the exception Message property value. sample as below.
catch (FaultException ex) { throw new InvalidPluginExecutionException("Err occurred.", ex.Message); }
- If you throw InvalidPluginExecutionException and do not provide a custom message, a generic default message is displayed in the error dialog. It is recommended that plug-ins only pass an InvalidPluginExecutionException back to the platform.
- If a synchronous plug-in returns an exception other than InvalidPluginExecutionException back to the platform, the error dialog is displayed to the user and the exception message with stack trace is also written to one of two places.
- For plug-ins not registered in the sandbox, the information is written to the Application event log on the server that runs the plug-in. Which you can view using Event Viewer (Run Command : eventvwr) then choose Application then search exceptions.
- For plug-ins registered in the sandbox, the exception message and stack trace is written to the Microsoft Dynamics CRM platform trace. For more information about tracing, see the Logging and Tracing section of the Debug a plug-In topic. Find a very detailed info on Debug, Trace and Logging in Plug-in here in MSDN site.
- Another way to log exception and informations passed from plugin is creating a custom entity and creating records catch section in plugin by using try block. But to implement this you have to think again as it again may impact the performance of the plugin if not properly handled. Another nice article you can find here in MSDN how to handle exceptions in code.
- If there is any exception in plugin and the code executes in database transaction then the plugin will rollback. so need to think the exception handling properly.
- You can use a tool crmdiagtool2011 to enable CRM tracing and capturing trace file in case of issue analysis. here you can download the tool.
-
Handling Exceptions in Custom Workflows Activities and workflows
- When we create a workflow if any exceptions occurs in any workflow step then the status of the workflow changes to Failed and If because of some condition check failed then the Workflow postpones forever by changing the status as waiting. If you check the workflow instance in System JOB you can get the info in Failure message area.
- If you are using any custom workflow activities then the proper way to handle exceptions is to throw a new instance of InvalidPluginExecutionException as shown below:
catch (FaultException ex) { throw new InvalidPluginExecutionException(ex); }
- As workflows are asynchonous so any error message from the workflow is not presented to the user in real time until unless user checks the workflow status by looking the system jobs area in advance find or process section. So for this scenario one way I can think of off the top of my head to notify the user of an exception would be to catch the errors and kick off an email (if it’s really necessary).
- Also in custom workflow we can handle exception by returning a output value from the custom step and by checking the value condition we can do other logic or stop the workflow with email activity or log entity record entry.
-
Handling Exceptions in Form Javascript
- We can handle javascript errors by implementing try…catch blocks also. For more issue analysis we can use F12 debugger for the script library to debug the javascript codes. here is a nice article you can read.
- Be careful while writing javascript as this codes are case sensitive. If you are calling any function then call by its exact name with same case.
- Use proper curley brashes mathces for the functions or conditions to avoid errors.
- To handle the unexpected errors in javascript here is a good article please read this how to implement the code.
- a sample exception handling code for javascript is given below.
function EnableDisableTestButton() { try { // Button custom rule checking } catch(err) { alert("Error in EnableDisabletestfunction. Error Message: " + err.message); return false; } }
- While using REST and SOAP use some existing library as in these libraries the exceptions are handled.
-
Handling Exceptions in Custom Web App for CRM
- Custom Web applications can be very tricky as many complex logic are implemented according to the business need.
- You can use the common exception handling methods explained in point-7 below.
- If it is a custom web page then you can redirect to an error handling page by catching the exception and showing a customized message.
- un-handled Exceptions are logged in Event Viewer in Applications link.
- For a complete asp.net error handling techniques refer this link. We can use below files to handle errors.
- Web.config
- Global.asax
- Default.aspx
- ExceptionUtility (to be put in the App_Code folder)
- GenericErrorPage.aspx
- HttpErrorPage.aspx
- Http404ErrorPage.aspx
- DefaultRedirectErrorPage.aspx
-
Handling Exceptions in Dialogs
- As Dialogs are synchronous processes so any error occurs in the dialog steps directly presented to the user in a error window.
- we can use custom workflow steps to handle some output value condition to do further logic.
- Dialogs Tooltip can be used to provide info to end user to prevent occurring any unexpected error because of wrong data input.
- As there is no way to validate the field values except selecting the data type of the prompt controls, if there is any error happens then Dialog stops with prompting an error by rolling back the operation.
-
Event Viewer Analysis and Logging
- Un-handled Exceptions are captured in Application event viewer on the server it self.
- If you run the command eventvwr then by selecting Application events then searching for the time stamp of exception then we can get the detailed trace and process details causing the exception.
- We can also create text files as log files for our applications which can be stored in a physical directory of server.
- We can also use an error entity with information. Anytime an error occurs we can create records for analysis.
- System JOB entity is used for asynchronous jobs (workflows, bulk deletions, data imports, Asnsh Plugins) error logging.
-
Common Exceptions
catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault> ex) { Console.WriteLine("The application terminated with an error."); Console.WriteLine("Timestamp: {0}", ex.Detail.Timestamp); Console.WriteLine("Code: {0}", ex.Detail.ErrorCode); Console.WriteLine("Message: {0}", ex.Detail.Message); Console.WriteLine("Inner Fault: {0}", null == ex.Detail.InnerFault ? "No Inner Fault" : "Has Inner Fault"); } catch (System.TimeoutException ex) { Console.WriteLine("The application terminated with an error."); Console.WriteLine("Message: {0}", ex.Message); Console.WriteLine("Stack Trace: {0}", ex.StackTrace); Console.WriteLine("Inner Fault: {0}", null == ex.InnerException.Message ? "No Inner Fault" : ex.InnerException.Message); } catch (System.Exception ex) { Console.WriteLine("The application terminated with an error."); Console.WriteLine(ex.Message); // Display the details of the inner exception. if (ex.InnerException != null) { Console.WriteLine(ex.InnerException.Message); FaultException fe = ex.InnerException as FaultException; if (fe != null) { Console.WriteLine("Timestamp: {0}", fe.Detail.Timestamp); Console.WriteLine("Code: {0}", fe.Detail.ErrorCode); Console.WriteLine("Message: {0}", fe.Detail.Message); Console.WriteLine("Trace: {0}", fe.Detail.TraceText); Console.WriteLine("Inner Fault: {0}", null == fe.Detail.InnerFault ? "No Inner Fault" : "Has Inner Fault"); } } }