Example: ExpressX exception handling in edmiNET API
There is now a way to throw an exception in ExpressX code that can be caught in the edmiNET binding.
Works on the query functions in ExpressX that has generic return type (generic or aggregate of generic)
To raise an .NET xpxException in edmiNET you need to create View_Entity Exception (as shown below) and return it in an Aggregate Of Exception.
We use Aggregate of Exception to allow for more than one exception as a chain of inner exceptions:
--------------------------------------------------------------------------------------------- -- Exception handling -- In the global section declare the following: -- GLOBAL -- GExceptions : Aggregate Of Exception := []; -- GException : Exception; -- ... -- END_GLOBAL; VIEW_ENTITY Exception; _Type_ : STRING; -- Either 'edmException' or 'xpxException' errCode : INTEGER; -- EDM error code as returned from xpxExceptionId errMessage : STRING; -- EDM error message as returned from xpxExceptionId userCode : INTEGER; -- Selfmade code userMessage : STRING; -- Selfmade message functionName : STRING; -- Function as returned from xpxExceptionId or selfmade lineNumber : INTEGER; -- Line number as returned from xpxExceptionId or selfmade. innerException : Exception; END_VIEW_ENTITY;
In the ExpressX code we recommend the following two exception handling utility functions:
- Function GetException(Message : String) : Aggregate Of Exception
- Procedure CancelException
Function GetException(Message : String) : Aggregate Of Exception;
   Local
      lInnerException : Exception;
     lMessage : String;
     lKeep : Boolean := True;
   End_Local;
   If NVL(xpxExceptionId.errCode, 0) <> 0 Then
      -- EDM error
     -- Avoid reporting the same error twice
     Repeat I := 1 To xpfSizeOf(GExceptions);
        If (GExceptions[I].errCode = xpxExceptionId.errCode) And
           (GExceptions[I].lineNumber = xpxExceptionId.lineNumber) Then
           lKeep := False;
           Escape;
        End_If;
     End_Repeat;
     If lKeep Then
        lInnerException := GException;
        New GException;
        GException._Type_        := 'edmException';
        GException.errCode       := xpxExceptionId.errCode;
        GException.errMessage    := xpfGetErrorText(xpxExceptionId.errCode);
        GException.functionName  := xpxExceptionId.functionName;
        GException.lineNumber    := xpxExceptionId.lineNumber;
        GException.innerException := lInnerException;
        lMessage := xpfStringPrintf('Line #%d: Exception. EDM Error number: %d, Message: %s', NVL(xpxExceptionId.lineNumber, xpxCurrentLine), GException.errCode, GException.errMessage);
        xpxPrintf('%s\n', lMessage); xpxDebugPrintf('%s\n', lMessage);
        GExceptions ++ GException;
      End_If;
   End_If;
   If NVL(Message, '') <> '' Then
      lInnerException := GException;
      New GException;
      GException._Type_        := 'xpxException';
      GException.userMessage   := Message;
      GException.innerException := lInnerException;
      lMessage := xpfStringPrintf('Line #%d: Exception: Message: %s', NVL(xpxExceptionId.lineNumber, xpxCurrentLine), GException.userMessage);
      xpxPrintf('%s\n', lMessage); xpxDebugPrintf('%s\n', lMessage);
      GExceptions ++ GException;
   End_If;
   Return(GExceptions);
End_Function;
Declare the follwing On_Error_Do block in the beginning of every function to ensure that all EDM errors are caught and that exceptions propagate upwards in the stack.
   On_Error_Do xpxThrow(GetException(?)); End_On_Error_Do;
Throw "soft" errors from code like this:
   xpxThrow(GetException('Something when wrong'));
To ignore an exception and reset exception chain:
   On_Error_Do cancelException; End_On_Error_Do;
Catch the XPXException in edmiNET like this:
  Â
edmiNet VB:
Try EnterpriseModel.NewQuery.Execute("CatDictionaryServices", "UpdateExchangeRequirementConceptAttribute", New Object() {New Instance(ProductPage.ERConceptId), New Instance(lGroupId), New Instance(lConceptId), Column.Name, NewValue}) RefreshRow = True Catch XPXEx As XPXException XtraMessageBox.Show(XPXEx.Message) Catch Ex As Exception XtraMessageBox.Show(Ex.ToString) End Try
edmiNet C#:
try { EnterpriseModel.NewQuery.Execute("CatDictionaryServices", "UpdateExchangeRequirementConceptAttribute", new object[] { new Instance(ProductPage.ERConceptId), new Instance(lGroupId), new Instance(lConceptId), Column.Name, NewValue }); RefreshRow = true; } catch (XPXException XPXEx) { XtraMessageBox.Show(XPXEx.Message); } catch (Exception Ex) { XtraMessageBox.Show(Ex.ToString); }
If there is a usermessage in the xpxException object this will be shown as the Message of the exception object. If there is no usermessage and there is a edmErrroCode the message will look like this:
Error number 11298: Illegal data type or data value of argument #1. Function: xpfGetInstanceModel Line number: 1581 Query function: CatDictionaryServices.UpdateExchangeRequirementConceptAttribute