Exception Handling in Delphi Datasnap REST Server

I am struggling with exception handling in my DATASNAP REST service (Delphi XE3, but also tried with Delphi 10 Seattle). Over the years, I have written half a dozen Windows services, and always include the TApplicationEvents component so that I can log any application exceptions in the Windows event log.

However, this behavior does not occur with the Datasnap service. The TApplicationEvents.OnException event never fires, so I assume that something else has an exception and processes it before it gets here.

The exception is displayed as a result of the web service method method, which is fine because it means that I can at least display something on the client side, but I would also like to catch it before so that I can handle different exceptions on the server side .

The only consistent way I've managed so far is to wrap each individual method in a try..except block and handle the exception in each method until the exception is recreated. However, using a web service of 20 methods and growth, this will not really expand.

I also tried to implement OnError, OnTrace and other events of some Datasnap components (TDSServer, TDSHTTPService, TDSTCPServerTransport, etc.), but they do not seem to work either.

Can anyone find something like this please?

+5
source share
1 answer

Tl; Dr: it is not implemented in an applicable way (in 10.1 Berlin).

I ran into the same problem, and after reading a large number of sources, I did not find a practical solution.

So, an exemplary (mine) StackTrace would look like this:

 MyClass::MyServerMethod() /* skipping some funny unimportant RTTI/TValue handling here */ System::Rtti::TRttiMethod::Invoke Dsreflect::TDSMethod::Invoke(TObject, TDSMethodValues) TDSServerConnectionHandler::DbxExecute(const TDBXExecuteMessage) TDSServerCommand::DerivedExecuteUpdate TExecuteCallback TDSService::Execute(const string, const TRequestCommandHandler, TExecuteCallback) TDSService::ProcessRequest(const string, const TRequestCommandHandler, TExecuteCallback) TDSRESTService::ProcessREST(const string, const string, const TArray<Byte>, const TRequestCommandHandler) TDSRESTService::ProcessGETRequest(const string, TStrings, TArray<Byte>, TRequestCommandHandler) TDSRESTServer::DoDSRESTCommand(TDSHTTPRequest, TDSHTTPResponse, string) TDSRESTServer::DoCommand(TDSHTTPContext, TDSHTTPRequest, TDSHTTPResponse) Dshttpwebbroker::TDSRESTWebDispatcher::DispatchRequest(TObject, Web::Httpapp::TWebRequest, Web::Httpapp::TWebResponse) 

Note. It is completely dependent on the use of DataSnap. In the above cases, requests are sent to the DataSnap API via TDSRESTWebDispatcher (starting with TIdCustomHTTPServer ).

  • Each Exception raised in ServerMethod will fall into TDSService::ProcessRequest .
  • In this procedure, every Exception caught, and ONLY its Message appended to TRequestCommandHandler->CommandList .
  • Further down, Message written as a JSON / DBX command to exit.

Therefore, we will never be able to handle the Exception object and access StackTrace or other information. Thus, this in itself is unacceptable and should change

The good news is that this procedure is virtual and can be overwritten. The bad news is that in the above example, you need to extend the TDSRESTService with your own ProcessRequest procedure (including your error handler), TDSRESTServer with your own DoDSRESTCommand (where the TDSRESTService is created into a monstrously large procedure) and TDSRESTWebDispatcher (depending on your use) .

My personal recommendation is not to use DataSnap.

Note. At the time of writing this question, I did not find any call to the OnError event.

0
source

Source: https://habr.com/ru/post/1237162/


All Articles