Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception Handler For ServiceClientBase

Tags:

servicestack

I want to handle all WebServiceException's thrown by my service client. Is there a good way to do this right now?

For example I'm passing a single ServiceClientBase around a windows forms app. I'm passing an api key to the server in an http header. For any request that api key isn't valid, I want to show a message box telling the user that the request was unauthorized and they should set the API key. But I don't want this code everywhere:

try
{
    _client.Get(new ReqDto());
}
catch (WebServiceException ex)
{
    if(ex.StatusCode == 401)
        Util.ShowUnauthorizedMessageBox();
}

Something like this would be nice:

_client.WebServiceExceptionHandler += TheHandler;

I know there's the local response filter that I can hook into, but I need the materialized WebServiceException.

I'm looking at ServiceClientBase.cs to see what I can do, but I'd appreciate any help. Thanks.

like image 846
Ronnie Overby Avatar asked Apr 18 '13 21:04

Ronnie Overby


2 Answers

If I may approach this as a design question, rather than an API question, then the answer is to wrap your service client. Personally, I have done something similar so I can log service exceptions on the client.

This could be a starting point:

public class MyServiceClient : IDisposable
{
    public ServiceClientBase ServiceClient { get; set; }

    string _serviceUri;
    public string ServiceUri
    {
        get { return _serviceUri; }
        set { _serviceUri = value; ServiceUriChanged(); }
    }

    public MyServiceClient()
    {
        ServiceUri = "http://127.0.0.1:8080";
    }

    public void Dispose()
    {
        ServiceClient.Dispose();
    }

    public TResponse Get<TResponse>(IReturn<TResponse> request)
    {
        try
        {
            return ServiceClient.Get(request);
        }
        catch (WebServiceException ex)
        {
            if(ex.StatusCode == 401)
                Util.ShowUnauthorizedMessageBox();
        }
    }

    void ServiceUriChanged()
    {
        if (ServiceClient != null)
            ServiceClient.Dispose();
        ServiceClient = new JsonServiceClient(ServiceUri);
    }
}

Over time you may find other benefits to this additional level of indirection, such as adding local caching, logging all requests & responses [to a debug console]. And, once it is in use in all your client code, it is pretty cheap to maintain.

As far as the API goes, I do not think it offers what you want. Personally, I've been pleased with it as it is (especially as the IReturn<T> interface helps when consolidating functions like the one you want). But, if you aren't happy with it, then you are one pull request away from a dialog with Demis on improving it. (-=

like image 166
Jacob Foshee Avatar answered Oct 07 '22 05:10

Jacob Foshee


This is a bit late to the game, but I was running into the same thing so began to dig into the source. There is actually a simple fix to this, override the HandleResponseException method in whatever ServiceClient you are using. Direct from the comments:

        /// <summary>
        /// Called by Send method if an exception occurs, for instance a System.Net.WebException because the server
        /// returned an HTTP error code. Override if you want to handle specific exceptions or always want to parse the
        /// response to a custom ErrorResponse DTO type instead of ServiceStack's ErrorResponse class. In case ex is a
        /// <c>System.Net.WebException</c>, do not use
        /// <c>createWebRequest</c>/<c>getResponse</c>/<c>HandleResponse&lt;TResponse&gt;</c> to parse the response
        /// because that will result in the same exception again. Use
        /// <c>ThrowWebServiceException&lt;YourErrorResponseType&gt;</c> to parse the response and to throw a
        /// <c>WebServiceException</c> containing the parsed DTO. Then override Send to handle that exception.
        /// </summary>

I personally am doing something like the following on my override of the JsonServiceClient

    protected override bool HandleResponseException<TResponse>(Exception ex, object request, string requestUri, Func<System.Net.WebRequest> createWebRequest, Func<System.Net.WebRequest, System.Net.WebResponse> getResponse, out TResponse response)
    {
        Boolean handled;
        response = default(TResponse);
        try
        {
            handled = base.HandleResponseException(ex, request, requestUri, createWebRequest, getResponse, out response);
        }
        catch (WebServiceException webServiceException)
        {
            if(webServiceException.StatusCode > 0)
                throw new HttpException(webServiceException.StatusCode, webServiceException.ErrorMessage);
            throw;
        }
        return handled;
    }
like image 28
Justin Pihony Avatar answered Oct 07 '22 04:10

Justin Pihony