DtaWin server exceptions

This forum is meant for questions and discussions about the X# language and tools
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am
Location: Germany

DtaWin server exceptions

Post by Karl-Heinz »

Hi Chris,

in the error.prg i see that you have added to the "Description :" etc. layout self:stacktrace, but the output is a bit confusing because in the resx file "ERROR_STACK" and "ERROR_CALLEDFROM" have the same value "called from". I think it´s better if the value of "ERROR_STACK" is "Stack" or maybe "Stacktrace"

Code: Select all


 <data name="ERROR_STACK" xml:space="preserve">
    <value>Called from</value>
  </data>
  <data name="ERROR_CALLEDFROM" xml:space="preserve">
    <value>Called from</value>
Some remarks about how server errors are handled in Dta and DtaDlg windows: If a self:server error happens the exception doesn´t reach automatically a global handler, only if a server is stored in a var.

Code: Select all

Method EnforceError1() class dtawin

  self:server:Fieldput ( #xxxxx , 123 )   // field doesn´t exist 


Method EnforceError2() class dtawin
local o as dbserver

	o := Dbserver { "foo" }

	o:Fieldput ( #xxxxx , 123 )   // field doesn´t exist



method Error(e)  class dtawin // this method is called if a self:server error happens

	e:Throw()   // forward the exception to the global handler 

the two attached images show the exception results. Note: the LocalServer.png shows the file and line number where the error occurred.

Any chance that a self:server exception goes directly to a global handler ?

BTW. Are there beside "DBSERVER" and "WCERROR" exceptions some more VO specific exceptions that use the "Description :" etc. layout ?

regards
Karl-Heinz
Attachments
SelfServer.png
SelfServer.png (72.35 KiB) Viewed 577 times
LocalServer.png
LocalServer.png (60.9 KiB) Viewed 577 times
User avatar
robert
Posts: 4520
Joined: Fri Aug 21, 2015 10:57 am
Location: Netherlands

DtaWin server exceptions

Post by robert »

Karl-Heinz,

These were my changes.
- ERROR_STACK should indeed have been StackTrace
- What do you mean with 'global error handler' ? Errors inside the framework will always be thrown. You need a try catch somewhere in your code to catch them. The only way to globally handle an error would be if the compiler would do something like this for every line of code:

Code: Select all

do while true
try
    // original source line
    exit
catch e as Exception
   // call errorblock code
   local lResult := eval(cbErrorBlock, e) as LOGIC // this will either quit the app or return a logic
   if lResult == TRUE // E_RETRY
       Loop
   else
        // how to handle default values?
    endif
end try
I personally think that will kill the performance of your apps and is not a good idea.

Robert
XSharp Development Team
The Netherlands
robert@xsharp.eu
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am
Location: Germany

DtaWin server exceptions

Post by Karl-Heinz »

Hi Robert,

ErrorDialogTabFormatException is a subclass of the X# ErrorDialog class where i do the text formating. All the hardcopies i´ve posted the last days show the content of this dialog.

Is there anything wrong in this kind of exception handling ?

Code: Select all

[STAThread];
FUNCTION Start() AS INT 
LOCAL oXApp AS XApp
LOCAL oDlg AS ErrorDialogTabFormatException 


	TRY
		oXApp := XApp{}
		oXApp:Start() 
		  
	CATCH e AS Exception

		oDlg := ErrorDialogTabFormatException { e } 
		oDlg:showDialog()
		
	END TRY
	
RETURN 0  


CLASS XApp INHERIT App 
 	
		
METHOD Start () CLASS XApp 
	   		
    	
....
	
	

END CLASS

regards
Karl-Heinz
User avatar
robert
Posts: 4520
Joined: Fri Aug 21, 2015 10:57 am
Location: Netherlands

DtaWin server exceptions

Post by robert »

Karl-Heinz,
This looks OK to me.
Is this what you call a 'global handler'. That should work.
The only 'problem' is that some of the VO SDK Classes do not call this but try to look for an error handler in a client and otherwise call the error handler registered with ErrorBlock().
For example the DbServer class does this:

Code: Select all

	IF IsArray( aClients ) .AND. nClients != 0 .AND. IsMethod( aClients[1], #Error )
			Send(aClients[1],#Error, oErr )
		ELSE
			lErrorProcessingSemaphor := FALSE
			Eval( ErrorBlock( ), oErr )
		ENDIF
If you want your error dialog to be called then you should set the ErrorBlock to something like this:

Code: Select all

ErrorBlock({|e| MyThrow(e)})
And add a function

Code: Select all

FUNCTION MyThrow(e as Exception)
    THROW e
Robert
XSharp Development Team
The Netherlands
robert@xsharp.eu
User avatar
wriedmann
Posts: 3755
Joined: Mon Nov 02, 2015 5:07 pm
Location: Italy

DtaWin server exceptions

Post by wriedmann »

Hi Karl-Heinz,

PMFJI: your error handler will work, if there is no other try/end try sequence.
Let me explain with a bit of pseudocode:

Code: Select all

function TestFunc()
DoSomething() // errors here will be catched by your handler
try
DoSomethingElse() // errors here will NOT be catched by your handler
end try
return nil
This is the big difference to VO where an error handler is set globally. In .NET the error handling is occurring all the time in the catch block of the try/end try sequence.
And begin/end sequence is translated to try/end try in X#.

I can see only one solution (and this solution is used internally in the WinForms classes, I think): the possibility to set a global error handler in the GUI and/or RDD classes. And then in relative classes ALL catch blocks must be changed to call this global error handler. That would be a major work, I think, but it could be the best compromise.
@Robert: what do you think about such a handler?

Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am
Location: Germany

DtaWin server exceptions

Post by Karl-Heinz »

Hi Robert

Thanks !

Yes, that´s what i call a "global handler" and the only problem i noticed so far is how to catch "self:server" errors correctly. Your advice how to handle this sounds promising, i´ll give it a try !

regards
Karl-Heinz
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am
Location: Germany

DtaWin server exceptions

Post by Karl-Heinz »

Hi Karl-Heinz,
PMFJI: your error handler will work, if there is no other try/end try sequence.
Hi Wolfgang,

Yes, that is what i expect. Let´s say i want to open a server not shared - though it´s already opened. The msginfo() Box popups and i see as expected the oscode 32.

Code: Select all


METHOD PshOpenAgain()		
LOCAL o AS FooServer
LOCAL bLastErrorHandler AS USUAL
LOCAL oError AS USUAL

 
	bLastErrorHandler := ErrorBlock( {|oErr| _Break(oErr)} ) 

	BEGIN SEQUENCE 
				
		o := FooServer{ , FALSE }	
	      
	RECOVER	USING oError
	
		msginfo ( "RECOVER" + crlf +; 
			"Description: " + oError:Description + crlf + ;
			"OS code: " + AsString ( oError:Oscode  )	)  
		
	END SEQUENCE 
	

	ErrorBlock(bLastErrorHandler)			
	
	 	
	RETURN SELF   

regards
Karl-Heinz
User avatar
wriedmann
Posts: 3755
Joined: Mon Nov 02, 2015 5:07 pm
Location: Italy

DtaWin server exceptions

Post by wriedmann »

Hi Karl-Heinz,

currently in .NET/X# the errorhandler would be ignored.

And the recover block would only be executed if in code that is executed in the FooServer constructor no exception handling is defined.
In .NET all error handling is occurring locally.
Please see this pseudo code:

Code: Select all

function Func1() as void
try
func2()
catch oEx as Exception
? oEx:Message
end try
return

function func2() as void
.... // errors here will be catched in the calling function
try
.... // errors here will NOT be catched in the calling function because they are already handled
catch oEx as Exception
? oEx:Message
end try
return
The only possibility to catch the errors inside the the try/end try block of func2 also in the catch block of func1 would be to throw a new exception in the catch block of func2 and passing the old exception as InnerException to the new one.

Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am
Location: Germany

DtaWin server exceptions

Post by Karl-Heinz »

Hi Wolfgang,

maybe i misunderstand you. When i run the DoFirstCall(), the VO and X# behaviour is exactly the same. Depending on which '? "Test " + u' line in the DoNextCall() is activated, i see either "Recover I" or "Recover II" in the same order. Of course, when i already enforce an error in the DoFirstCall() is see either
the default VO-Error dialog , or in X# my exception dialog.

Code: Select all

FUNCTION DoFirstCall()  AS VOID
LOCAL bLastErrorHandler AS USUAL
LOCAL oError AS USUAL
  
//  LOCAL u := 12.34 AS USUAL
// 
// ? "Test " + u    // default VO-Error Dialog appears,  or in X# my exception dialog



	bLastErrorHandler := ErrorBlock( {|oErr| _Break(oErr)} ) 
         

	BEGIN SEQUENCE 
				
		DoNextCall()
	      
	RECOVER	USING oError 
		
 		MsgInfo ( "RECOVER I" )  
		
	END SEQUENCE 
	

	ErrorBlock(bLastErrorHandler)	
	               
	               
	               
	RETURN 	

FUNCTION DoNextCall()  AS VOID
LOCAL bLastErrorHandler AS USUAL
LOCAL oError AS USUAL
LOCAL u := 12.34 AS USUAL 


	bLastErrorHandler := ErrorBlock( {|oErr| _Break(oErr)} ) 

    
//     ? "Test " + u   //  "RECOVER1" 


	BEGIN SEQUENCE
		
       ? "Test " + u   //  "RECOVER2"  

	      
	RECOVER	USING oError 
		

		MsgInfo ( "RECOVER II" )  
		
	END SEQUENCE 
	

	ErrorBlock(bLastErrorHandler)	
	
	RETURN 		

i think we need a website blog like "X# Errorhandling to the max" , or similar ;-)

regards
Karl-Heinz
User avatar
wriedmann
Posts: 3755
Joined: Mon Nov 02, 2015 5:07 pm
Location: Italy

DtaWin server exceptions

Post by wriedmann »

Hi Karl,
When i run the DoFirstCall(), the VO and X# behaviour is exactly the same. Depending on which '? "Test " + u' line in the DoNextCall() is activated, i see either "Recover I" or "Recover II" in the same order. Of course, when i already enforce an error in the DoFirstCall() is see either the default VO-Error dialog , or in X# my exception dialog.
That is exactly what I meant....

But I have now made some tests, and I have seen that the development team has implemented the ErrorBlock() function, and when you do something like this:

Code: Select all

begin sequence
uValue := 12.45
System.Console.WriteLine( string( "Hello " + uValue ) )
recover
Eval( ErrorBlock() )
end sequence
effectively the ErrorBlock is executed, and so the VO class libraries seem to have already the central point for errorhandling.

Therefore if you write your own code with begin/end sequence or try/end try you can should use the same mechanism, and use the stored ErrorBlock.

So I have to revise what I've been thinking.....

I will try to write an article about it in the docs wiki: how errorhandling in migrated code can be handled.
What I'm interested in: how the code recover block in the begin/end sequence block is translated by the compiler.

Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
Post Reply