Page tree

If you have a comment on this topic, contact Aptify Documentation. If you want to return to the Aptify Community Site, please click here.

Skip to end of metadata
Go to start of metadata

Overview

The preferred means for surfacing errors to callers is to throw strongly typed exceptions from your business logic and to register error handlers that turn the results into meaningful HTTP response messages.

This is what the stock e-Business process components are doing. You will find documentation about what exceptions are thrown in the .NET documentation for the specific process components. 

All uncaught exceptions are translated into a JSON object with the following properties:

  • Type - The kind of error that was generated. Typically it is the class name of the exception with the word 'Exception' removed. If the business logic throws an OrdersException then type will be 'Orders'. If it throws an ArgumentException the type is 'Argument'. If it throws a SecurityRequirementFailedException the type is 'SecurityRequirementFailed'. Both errorCode and Type are required to completely identify the error.
  • ErrorCode - a numeric identifier that further describes the error. Within each type, there are numeric codes that have explicit meanings. For example, the type of 'Order' can have errors codes of
    • 401 – add product failed because it is not a meeting product
    • 411 – add product failed because the product is not sold
    • 450 – no inventory is available for the product and backorder is not allowed
    • 400 – an unknown error occurred during add product
    • 700 – an unknown error occurred attempting to create payment information

Both errorCode and Type are required to completely identify the error. Numeric error codes can be reused for different types. The type 'ShoppingCart' could define an errorCode 700 that means 'invalid coupon code'.

  • Message - a string message that tells us what the problem is. This is almost always the exception's message property.
  • ResponseIdentifier - a server generated GUID that can be found in event viewer on the services web server to find more information about the error.  This can be used for troubleshooting.  If you are getting a response with no message, event viewer should have the full exception logged with the guide

Old endpoints do not conform to this standard yet. If you browse the help page for your services site, any endpoints that start with 'A{something}' are the old style of endpoints.

New endpoints that fail model validation do not conform to this standard yet. Model validation would be any input restrictions you see in the online endpoint help documentation, like fields that are required but not sent by the client. We will be updating model validation to this format before release.

In addition to the JSON object on the response body, an HTTP status code must be assigned to the response.  The framework will blank out the message property on the JSON object for any HTTP status codes >= 500.  These are considered internal server errors and the assumption is the message property may contain sensitive information that is not appropriate for end users to see.  HTTP status codes >= 400 and < 500 are assumed to be client facing messages and the message property will be populated.  Regardless the entire exception is always written to the Aptify Exception Manager.  

The HTTP status code on the response is not the same thing as the errorCode on the JSON object.

Example Error

As an unauthenticated user issue the following service request in your HTTP client

GET {{serviceRoot}}/ProfilePersons/1

Here is the response as shown in POSTMAN

Notice that the HTTP status code is 400 Bad Request and the errorCode is zero.  You can then take the responseIdentifier value and search for it in Event Viewer on the web server running services to find additional details.  

How do I know what errorCode value is available for a particular exception type?

By looking at the .NET documentation for the assembly that defines the exception.  You will see a class named ErrorCodes that lists them all out.  For example, the ShoppingCartInterfaces assembly defines the ShoppingCartException class.  This assembly also has an ErrorCodes class that lists out the possible error code values.  Similarly, the AptifyOrdersEntity assembly defines the OrdersException class.  This assembly also has a new ErrorCodes class that lists out the possible values and their meaning.  

Registering New Error Handlers

If you are creating new strongly typed exceptions to throw you need something to handle them.  The translation of exceptions to the JSON object is handled by implementations of ServicesExceptionHandling.IExceptionResponseHandler.  You do not need to implement this interface directly.  If the default JSON object format is acceptable for you, you should instead inherit ServicesExceptionHanding.AbstractExceptionResponseHandler.  This abstract class implements most of the behavior described in this document.  There is one abstract method that must be implemented to determine the correct HttpStatusCode for the response.  The abstract class will take care of blanking out the message property on the JSON object based on the HttpStatusCode.  You should also implement ServicesExceptionHandling.ICustomExceptionResponseHandler.  Implementing this interfaces allows your implementations to go first when handling exceptions, ensuring your configurations take priority over stock behavior.  

Do I have to register a new handler for every exception type I plan on throwing?

No.  If the framework cannot find an explicit handler registered for the exception a default handler will be applied.  This handler treats all exceptions as internal server errors and returns a HTTP status code of 500.  You only need to register a handler if you want other status codes to be used or the message property to be surfaced to the caller.  

How do I register my own error handler?

First, name your handler class with the convention {exceptionType}ResponseHandler.  So if your exception class is CustomerException your handler class would be named CustomerExceptionResponseHandler.  This is the default pattern AbstractExceptionRepsonseHandler uses in its CanHandle method.  Second, register your handler as a named instance of ICustomExceptionResponseHandler through through the DI container.  This ensures your exception handler will execute before any stock handlers.  For example:  

public class Installer : ISecondaryUnityInstaller
{
    public void Install(IUnityContainer container)
    {
        container.RegisterType<ICustomExceptionResponseHandler, CustomerExceptionResponseHandler>(typeof(CustomerExceptionResponseHandler).FullName);
    }
}

Can I change the default exception handler?

Yes.  Register your new handler as a named instance of IExceptionReponseHandler through the DI container with the name 'default'.  For example:

public class Installer : ISecondaryUnityInstaller
{
    public void Install(IUnityContainer container)
    {
        container.RegisterType<IExceptionResponseHandler, CustomDefaultExceptionResponseHandler>("default");
    }
}

Any exceptions that do not have an explicit handler will be processed by this one.  

You can find more information about developing your own exception handler and a sample ExceptionHandler project in this Support portal Solution Article: 

https://aptify.freshdesk.com/support/solutions/articles/6000244470-overriding-error-handling-in-e-business-6