Skip to content

Solid.Http.Extensions.ExceptionMapper Extending

HX-Rd edited this page May 30, 2018 · 4 revisions

Extending

There are two mappers set by default by the extension, SolidHttpDefaultExceptionMapper and SolidHttpModelExceptionMapper, and they map the exceptions SolidHttpRequestException and SolidHttpRequestModelException. In this section we will create a new mapper that will map the exception CustomException

Now lets say that we are calling an API that returns some custom body on exceptions. In our example lets say the exception contract is like so

{
    "cust1": "SomeVal1",
    "cust2": "SomeVal2",
    "cust3": "SomeVal3"
}

After shaking your head and shouting who designed this atrocity its time to get to work. Now we are going to make a exception that has all the goodies in the SolidHttpRequestException but these cust attribues as well.
Lets start with the exception

    [Serializable]
    public class CustomException : SolidHttpRequestException
    {
        public CustomException() { }
        public CustomException(string message) : base(message) { }
        public CustomException(string message, Exception inner) : base(message, inner) { }
        protected CustomException(
          System.Runtime.Serialization.SerializationInfo info,
          System.Runtime.Serialization.StreamingContext context) : base(info, context) { }

        public string Cust1
        {
            get
            {
                return this.Data["Cust1"] as string;
            }
            set
            {
                this.Data["Cust1"] = value;
            }
        }
        public string Cust2
        {
            get
            {
                return this.Data["Cust2"] as string;
            }
            set
            {
                this.Data["Cust2"] = value;
            }
        }
        public string Cust3
        {
            get
            {
                return this.Data["Cust3"] as string;
            }
            set
            {
                this.Data["Cust3"] = value;
            }
        }

Note that you do not have to derive from SolidHttpRequestException but I would recommend it, then you will get strong types on the attributes in the exception (StatusCode, Headers, Body and ReasonPhrase), but if you just derive from exception you can still get these values from the Data dictionary.
Now that we have our exception. Lets write our mapper.

    public class CustomExceptionMapper : SolidHttpExceptionMapper<CustomException>
    {
        public async override Task<CustException> MapException(HttpResponseMessage response, IServiceProvider serviceProvider, string message = null)
        {
            message = "Custom exception message, probably better to get it from the response, but you can do what you want :)";
            var ex = await base.MapException(response, serviceProvider, message);
            var errorObj = await DeserializeError<CustomExceptionModel>(response, serviceProvider);
            ex.Cust1 = errorObj.Cust1;
            ex.Cust2 = errorObj.Cust2;
            ex.Cust3 = errorObj.Cust3;
            return ex;
        }
    }

When you call the base objects MapException you get the StatusCode and the other attributes on SolidHttpRequestException. The DeserializeError deserializes the response if it can using the same deserialization techniques as Solid.Http ( getting the mime type of the content and seeing if it has a deserializer for it )
Now we have everything we need, now we just have to wire it up. We do that in the starup class.

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        var customMapper = new CustomExceptionMapper();
        services.AddSolidHttp()
                .AddExceptionMappings(new ExceptionMappingOptions
                {
                    Mappers = new List<IExceptionMapper>
                    {
                        customMapper
                    },
                    CustomDefaultMapper = customMapper
                });
    }
}

Now we set this up to be our default mapper so we can use it like so

        try
        {
            var resource = _client.GetAsync("exceptionEndpoint")
                                  .ThrowsException()
                                  .As<Resource>();
        }
        catch(CusomException ex) when (ex.Cust1 == "Custom message")
        {
            // Handle the Cust1 == "Custom message" here
        }
        catch(SolidHttpRequestException ex)
        {
            // Handle the rest here
        }

But of cause you don't have to use this as the default mapper. This works as well

        try
        {
            var resource = _client.GetAsync("exceptionEndpoint")
                                  .ThrowsException<CustomException>()
                                  .As<Resource>();
        }
        catch(CusomException ex) when (ex.Cust1 == "Custom message")
        {
            // Handle the Cust1 == "Custom message" here
        }
        catch(SolidHttpRequestException ex)
        {
            // Handle the rest here
        }

Clone this wiki locally