xsharp.eu • Error handling in X# vs VO - Page 3
Page 3 of 3

Error handling in X# vs VO

Posted: Fri Mar 12, 2021 3:21 pm
by IanB
Hi All

I've started using X# and finding it amazing how i can just copy/paste code from VO (2.5b) into Visual Studio and it nearly (99.9%) works. Just having an issue with Error Handling.... and using ErrorBlock() - i can see examples about setting an ErrorBlock but this doesn't work. I was then told about "FirstChanceException" in .net and i've put an example together below that will work (with very little change) for our VO Web Application. (i can see there is a open issue here https://github.com/X-Sharp/XSharpPublic/issues/111)

Below is a working example and what it does

1. Set a ErrorBlock() as you would do in VO
2. Set FirstChanceException to call function on error FirstChanceHandler (and UnhandledException if you want)
3. This then checks ErrorBlock to see if there is one defined, and calls it. (you could then write to Audit Trail etc.
4. FirstChanceHandler then returns to RECOVER statement , (ti stores the VO Error in a Thread Store so we can get it back later)
5. In the Recover , it could check the Error (from the Thread) so see what to do (if anything), in my example i see if i can retry.

I know it doesn't continue with the next line (as in VO), but it does use ErrorBlock which i couldn't seem to do, and you only need to change code in your recover if you need to access the Error !

Ian

-------------

Code: Select all

USING VO
USING System.Threading

BEGIN NAMESPACE Test

	FUNCTION Start() AS VOID STRICT

		LOCAL x AS USUAL

		System.AppDomain.CurrentDomain:UnhandledException += ExceptionHandler
		System.AppDomain.CurrentDomain:FirstChanceException += FirstChanceHandler

		ErrorBlock({|oError| MyErrorHandler(oError) })	

		x:=1

		DO WHILE TRUE
			BEGIN SEQUENCE
				x:=x+"Hello"
       
	        RECOVER
				LOCAL oError AS Error
            
	            oError:=GetError()
            
	            IF ! oError==NULL_OBJECT .AND. oError:CanRetry
		            x:=""  // So shouldn't crash next time */
			        LOOP
				ENDIF
			END SEQUENCE        

			EXIT
       ENDDO

	INTERNAL FUNCTION MyErrorHandler(oError AS Error) AS VOID

        IF ! oError==NULL_OBJECT
/* Set Can Retry for our Test */            
			oError:CanRetry:=TRUE
		ENDIF

	INTERNAL FUNCTION GetError() AS Error

		LOCAL oError AS Error

/* Get Current Error from Thread (using GetData) and NULL error in Thread */
		oError:=(Error) Thread.GetData(Thread.GetNamedDataSlot("Error"))
		Thread.SetData(Thread.GetNamedDataSlot("Error"),NULL)
            
		RETURN oError            
       
	INTERNAL FUNCTION FirstChanceHandler( sender AS OBJECT, args AS System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs) AS VOID
		
        LOCAL oError AS Error
		LOCAL bErrorHandler AS CODEBLOCK          

		Thread.SetData(Thread.GetNamedDataSlot("Error"),oError)              

		oError:=ErrorBuild(args:Exception)  
		bErrorHandler:=ErrorBlock()
        IF ! bErrorHandler==NULL_CODEBLOCK
			eval(bErrorHandler,oError)
		ENDIF    
/* Store Error in Thread (SetData) so we can get it back later */        
		Thread.SetData(Thread.GetNamedDataSlot("Error"),oError)
        
	STATIC FUNCTION ExceptionHandler( sender AS OBJECT, args AS UnhandledExceptionEventArgs) AS VOID
/* Can do the Same as the above */		

END NAMESPACE

Error handling in X# vs VO

Posted: Fri Mar 12, 2021 3:33 pm
by wriedmann
Hi Ian,
please see this page here:
https://docs.xsharp.it/doku.php?id=begin_end_sequence
The main problem is that the .NET runtime does not knows a global error handler.
Whan you can do (and what the X# team has done for their runtime): set an error handler and evaluate it in a try catch sequence in your code whenever an error is occurring.
That may be a sample code (.NET style, not VO style):

Code: Select all

try
.....
catch oEx as Exception
if self:ExceptionHandler != null
  self:ExceptionHandler:Invoke( oEx )
endif
end try
Wolfgang

Error handling in X# vs VO

Posted: Fri Mar 12, 2021 4:09 pm
by IanB
I understand, but using FirstChanceException you can call say a function/method to write the error (just like we did in VO), and then return to the Recover / Try Catch etc.

But in 99% of my cases, i just want to record the error , and then in my recovery i already have code to Rollback Transaction (ADS) and then just exit. So it means that i don't need to add 1000's of lines to all my recovery to record the error (as that's already done).

Hope that makes sense.