There is now a way to throw an exception in ExpressX code that can be caught in the edmiNET binding's Execute function of the query object from the xpx machine. .
Works on externally callable 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 a view_entity like this View_Entity Exception (as shown below) and return it in an aggregateAggregate Of Exception.
We use Aggregate of Exception to allow for more than one exception as a chain of inner exceptions:
Code Block |
---|
title | Exception View Entity |
---|
linenumbers | true |
---|
|
---------------------------------------------------------------------------------------------
-- 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
...
title | Express Helper functions and procedures |
---|
linenumbers | true |
---|
collapse | true |
---|
...
-- Create an new innermost exception representing the current xpxExceptionId object
Function GetEDMException : Aggregate Of Exception;
GExceptions := [];
CreateEDMException;
Return(GExceptions);
End_Function;
Procedure NewEDMException;
GExceptions := [];
CreateEDMException;
End_Procedure;
-- Create an new "selfmade" innermost exception
Function GetException(Message : String) : Aggregate Of Exception;
GExceptions := [];
NewOuterException(Message);
Return(GExceptions);
End_Function;
Procedure NewException(Message : String);
GExceptions := [];
NewOuterException(Message);
End_Procedure;
-- Create an new outer exception on the previous (inner) exception
Function GetOuterException(Message : String) : Aggregate Of Exception;
NewOuterException(Message);
Return(GExceptions);
End_Function;
Procedure NewOuterException(Message : String);
Local
lInnerException : Exception;
End_Local;
lInnerException := GException;
New GException;
GException._Type_ := 'xpxException';
GException.userMessage := Message;
GException.innerException := lInnerException;
GExceptions ++ GException;
End_Procedure;
Procedure CreateEDMException;
Local
lInnerException : Exception;
End_Local;
lInnerException := GException;
New GException;
GException._Type_ := 'edmException';
GException.errCode := xpxExceptionId.errCode;
GException.errMessage := xpxExceptionId.errMessage;
GException.functionName := xpxExceptionId.functionName;
GException.lineNumber := xpxExceptionId.lineNumber;
GException.innerException := lInnerException;
GExceptions ++ GException;
End_procedure;
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;
Code Block |
---|
title | Express Helper functions and procedures |
---|
linenumbers | true |
---|
collapse | true |
---|
|
-- To ignore an exception from lower level and continue
-- execution as normal call the following function.
Procedure CancelException;
GExceptions := [];
GException := ?;
End_Procedure;
---------------------------------------------------------------------------------------------
|
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:
Code Block |
---|
language | vb |
---|
title | .Net VB Example |
---|
linenumbers | true |
---|
|
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#:
Code Block |
---|
language | c# |
---|
title | .NET C# Example |
---|
linenumbers | true |
---|
|
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:
Code Block |
---|
|
Error number 11298: Illegal data type or data value of argument #1.
Function: xpfGetInstanceModel
Line number: 1581
Query function: CatDictionaryServices.UpdateExchangeRequirementConceptAttribute |