1

In line with the ServiceStack documentation, we have a global service exception handler. The docs say that this handler should log the exception then call DtoUtils.HandleException, like this:

private object LogServiceException(object request, Exception exception)
{
    var message = string.Format("Here we make a custom message...");
    _logger.Error(message, exception);
    return DtoUtils.HandleException(this, request, exception);
 }

This results in the error being logged twice, since DTOUtils.HandleException also logs it, in a less customised format. Yes, I much prefer this to the DTOUtils logging and don't want to just use that.

How do we turn off DTOUtils logging while retaining the rest of the functionality? Nobody likes getting twice as many error emails as they should.

Anthony
  • 5,176
  • 6
  • 65
  • 87
  • Is it safe to assume that you require the logging in your exception handler? If not why not simply remove it from there and let DtoUtils log the exception? – Mike Sep 18 '13 at 16:29
  • If you create the ServiceRunner, as you can read in the same documentation, the error is logged twice ? [Fine grain error handling using the New API's ServiceRunner](https://github.com/ServiceStack/ServiceStack/wiki/Error-Handling) – stefan2410 Sep 18 '13 at 21:25
  • Yes, it is logged twice with a ServiceRunner. Docs on ServiceRunner are quite sparse, but it looks like if you make your own ServiceRunner you can logthe url from IRequestContext, and then you call "return base.HandleException(requestContext, request, ex);" .. which calls DtoUtils.HandleException which does 2 things - make the error response and logs the exception. I wish it was more Single-responsibility. – Anthony Sep 19 '13 at 14:45
  • I have not time to test it. But in my code I don't return the base.HandleException or I return it, under condition. I create a response using DtoUtils.CreateErrorResponse ... In this case, it is logged twice, once, or not at all ? – stefan2410 Sep 19 '13 at 18:51
  • Yes, CreateErrorResponse looks like the way to go and I am testing it out. Can you update the answer? – Anthony Sep 20 '13 at 13:04

2 Answers2

2

I hope the following code solves your problem.

based on the documentation New API, Custom Hooks, ServiceRunner

and Fine grain error handling using the New API's ServiceRunner

in AppHost.Configure

   LogManager.LogFactory = new ServiceStack.Logging.Support.Logging.ConsoleLogFactory();   

then in AppHost class

         public override IServiceRunner<TRequest> CreateServiceRunner<TRequest>(ActionContext      actionContext)
          {
               return new MyServiceRunner<TRequest>(this, actionContext);
            }  

in the ServiceRunner class

       public class MyServiceRunner<T> : ServiceRunner<T>
       {

            public override object HandleException(IRequestContext requestContext, T request, Exception ex)
              {
                  if ( isYourCondition ) 
                  {
                        ResponseStatus rs = new ResponseStatus("error1", "your_message");
                        // optionally you can add custom response errors
                             rs.Errors = new List<ResponseError>();
                             rs.Errors.Add(new ResponseError());
                             rs.Errors[0].ErrorCode = "more details 2";

                            // create an ErrorResponse with the ResponseStatus as parameter
                            var errorResponse = DtoUtils.CreateErrorResponse(request, ex, rs);
                             // log the error
                             Log.Error("your_message", ex);
                             return errorResponse;

                   }
                   else
                        return base.HandleException(requestContext, request, ex);
               }

            }

if you return the base.HandleException, it calls internally the DtoUtils.HandleException. You will see in console, one log error only.

In client, if you handle the WebServiceException for custom errors.

            catch (WebServiceException err)
            {
                if ( err.ResponseStatus.Errors != null)
               { // do something with err.ResponseStatus.Errors[0].ErrorCode; 
               }
            }
stefan2410
  • 1,931
  • 2
  • 16
  • 21
1

Do not call DtoUtils.HandleException as it logs the error. Don't call ServiceRunner.HandleException either, it calls DtoUtils.HandleException.

Call DtoUtils.CreateErrorResponse to make the response (it is used by DtoUtils.HandleException). The ToResponseStatus helper is also in DtoUtils

My AppServiceRunner is now like this:

public class AppServiceRunner<T> : ServiceRunner<T>
{
    public AppServiceRunner(AppHost appHost, ActionContext actionContext)
        : base(appHost, actionContext)
    {
    }

    public override object HandleException(IRequestContext requestContext,
        T request, Exception ex)
    {   
        LogException(requestContext, request, ex);

        var responseStatus = ex.ToResponseStatus();
        return DtoUtils.CreateErrorResponse(request, ex, responseStatus);
    }

    private void LogException(IRequestContext requestContext, T request, Exception ex)
    {
        // since AppHost.CreateServiceRunner can be called before AppHost.Configure
        // don't get the logger in the constructor, only make it when it is needed
        var logger = MakeLogger();
        var requestType = typeof(T);
        var message = string.Format("Exception at URI:'{0}' on service {1} : {2}",
            requestContext.AbsoluteUri, requestType.Name, request.ToJson());

        logger.Error(message, ex);
    }

    private static ILog MakeLogger()
    {
        return LogManager.GetLogger(typeof(AppServiceRunner<T>));
    }
}

Now the only service errors that I get are those generated by this code.

Anthony
  • 5,176
  • 6
  • 65
  • 87
  • Why do you think that my answer never call DtoUtils.HandleException directly; or indirectly ? Did you read my answer ? I don't understand you. – stefan2410 Sep 20 '13 at 14:32
  • your question was about the "the error being logged twice...nobody likes getting twice as many error". – stefan2410 Sep 20 '13 at 14:43
  • This did not work for me. ServiceStack still writes to the log on its own. – Facio Ratio Apr 28 '15 at 19:58
  • Actually it did work, but I had an error in a call to another service, and ServiceClientBase always writes errors regardless of any configuration. – Facio Ratio Apr 28 '15 at 20:33