Archived
Adding Error Handler To The Pipeline Ice RPC
Forgive me if the answer to this is in documentation somewhere, but I search for ages and couldn't find it.
As I said in a previous post I am writing an application that uses both SignalR and Ice RPC.
SignalR has the ability to add an error handler to the server pipeline in order to avoid having to wrap every single call within a try catch, thus saving code. From that error handler I am able to access context and log the error on the server.
I have searched the web for something a similar thing for Ice RPC, but I haven't being about the even find anything about general handling, on the server side.
Can you please help?
I am using C# on the server side.
Comments
-
Hi Andrew,
You can implement this using a dispatch interceptor, the interceptor will catch any exception throw by servant dispatch log the exception and rethrow it, should be something like
class Interceptor : Ice.DispatchInterceptor { private readonly Ice.Object _servant; internal InterceptorI(Ice.Object servant) => _servant = servant; public override Task<Ice.OutputStream> dispatch(Ice.Request request) { Ice.Current current = request.getCurrent(); Ice.Logger logger = current.adapter.getCommunicator().getLogger(); try { return _servant.ice_dispatch(request); } catch (Exception ex) { logger.error($"error dispatching operation {current.operation}\n{ex}"); throw; } } }
And then when creating your servants you wrap them in an interceptor for adding to the adapter
adapter.add(new Interceptor(new HelloI()), Ice.Util.stringToIdentity("hello"));
see also:
- https://doc.zeroc.com/ice/3.7/server-side-features/dispatch-interceptors
- https://github.com/zeroc-ice/ice-demos/tree/3.7/csharp/Ice/interceptor
Cheers,
Jose0 -
Thanks for your help.
You gave me what I wanted.I had to make some changes and I will post them here for the benefit of future readers.
I am still learning ICE, so if anyone knows better than me please say so.
internal class LoggingInterceptor : Ice.DispatchInterceptor { ... public override Task<Ice.OutputStream> dispatch(Ice.Request request) { Task<Ice.OutputStream> task = _servant.ice_dispatch(request); task?.ContinueWith( t => { if (t.IsFaulted) { LogMessage(t.Exception?.ToString()); } } ); return task; } ... }
Under the rules of C# if you return a task but don't await it the exception it won't be caught.
'ContinueWith' was recommended in the Ice doco in the first link as a way to wait for the task to complete.
I tried it just like in the code above and it worked.Also note I think that there is a typo in this line of the previous answer:
internal InterceptorI
I think it should be:
internal Interceptor
Otherwise it is not a valid constructor.
I do have one burning question. 'ice_dispatch' returns null several times before actually returning a task that can be awaited, hence the '?.' Any ideas?
Thanks for the help.
0 -
You are right, my sample only works with synchronous dispatch, in which case all exceptions are thrown synchronously.
Maybe a bit simpler
public override async Task<Ice.OutputStream> dispatch(Ice.Request request) { Ice.Current current = request.getCurrent(); Ice.Logger logger = current.adapter.getCommunicator().getLogger(); try { return _servant.ice_dispatch(request) is Task<Ice.OutputStream> task ? await task : null; } catch (Exception ex) { logger.error(ex.ToString()); throw; } }
0