C# REST / Http Client Abstraction I have a REST library. These are the abstractions. Have I missed anything that a developer would need to use this in a dependency injection / IoC Container scenario? Anything that bothers you about this? 

All Code Here

public interface IRestClient
{
    IRestHeadersCollection DefaultRequestHeaders { get; }
    TimeSpan Timeout { get; set; }
    Task DeleteAsync(Uri queryString);
    Task DeleteAsync(Uri queryString, CancellationToken cancellationToken);
    Task&lt;RestResponse&lt;TReturn&gt;&gt; GetAsync&lt;TReturn&gt;();
    Task&lt;RestResponse&lt;TReturn&gt;&gt; GetAsync&lt;TReturn&gt;(Uri queryString);
    Task&lt;RestResponse&lt;TReturn&gt;&gt; GetAsync&lt;TReturn&gt;(Uri queryString, CancellationToken cancellationToken);
    Task&lt;RestResponse&lt;TReturn&gt;&gt; PatchAsync&lt;TReturn, TBody&gt;(TBody body, Uri queryString);
    Task&lt;RestResponse&lt;TReturn&gt;&gt; PatchAsync&lt;TReturn, TBody&gt;(TBody body, Uri queryString, CancellationToken cancellationToken);
    Task&lt;RestResponse&lt;TReturn&gt;&gt; PostAsync&lt;TReturn, TBody&gt;(TBody body, Uri queryString);
    Task&lt;RestResponse&lt;TReturn&gt;&gt; PostAsync&lt;TReturn, TBody&gt;(TBody body, Uri queryString, CancellationToken cancellationToken);
    Task&lt;RestResponse&lt;TReturn&gt;&gt; PutAsync&lt;TReturn, TBody&gt;(TBody body, Uri queryString);
    Task&lt;RestResponse&lt;TReturn&gt;&gt; PutAsync&lt;TReturn, TBody&gt;(TBody body, Uri queryString, CancellationToken cancellationToken);
}

public interface IRestClientFactory
{
    IRestClient CreateRestClient(Uri baseUri);
    IRestClient CreateRestClient();
}

public interface IRestHeadersCollection : IEnumerable&lt;KeyValuePair&lt;string, IEnumerable&lt;string&gt;&gt;&gt;
{
    void Add(string name, string value);
    void Add(string name, IEnumerable&lt;string&gt; values);
    void Clear();

    IEnumerable&lt;string&gt; this[string name]
    {
        get;
    }

    bool Contains(string name);
}

public partial interface ISerializationAdapter
{
    /// &lt;summary&gt;
    /// Takes an object of Type T and converts it to binary data
    /// &lt;/summary&gt;
    Task&lt;byte[]&gt; SerializeAsync&lt;T&gt;(T value);

    /// &lt;summary&gt;
    /// Takes binary data and converts it to an object of type T
    /// &lt;/summary&gt;
    Task&lt;T&gt; DeserializeAsync&lt;T&gt;(byte[] data);
}

public interface ITracer
{
    void Trace(HttpVerb httpVerb, Uri baseUri, Uri queryString, byte[] body, TraceType traceType, int? httpStatusCode, IRestHeadersCollection restHeadersCollection);
}

public class RestResponse&lt;TBody&gt; : RestResponse
{
    public TBody Body { get; }

    public RestResponse(TBody body, IRestHeadersCollection restHeadersCollection, int statusCode, object underlyingResponse) : base(restHeadersCollection, statusCode, underlyingResponse)
    {
        Body = body;
    }

    #region Implicit Operator
    public static implicit operator TBody(RestResponse&lt;TBody&gt; readResult)
    {
        return readResult.Body;
    }

    public TBody ToTBody()
    {
        return Body;
    }
    #endregion
}

public class RestResponse
{
    #region Public Properties
    public int StatusCode { get; }
    public object UnderlyingResponse { get; }
    public IRestHeadersCollection Headers { get; }
    #endregion

    #region Constructor
    public RestResponse(IRestHeadersCollection restHeadersCollection, int statusCode, object underlyingResponse)
    {
        StatusCode = statusCode;
        UnderlyingResponse = underlyingResponse;
        Headers = restHeadersCollection;
    }
    #endregion
}


Originally I thought it might be useful to allow task async calls for serialization/deserialization but I've come to think that this is a bit redundant... Any thoughts on this?
IRestClient looks over-engineered. All of those helper members merge down to one common Call which can make the interface much simpler to define.

public interface IRestClient {
    IRestHeadersCollection DefaultRequestHeaders { get; }
    string DefaultContentType { get; set; }
    TimeSpan Timeout { get; set; }
    Task&lt;RestResponse&lt;TReturn&gt;&gt; SendAsync&lt;TReturn&gt;(RestRequest request, CancellationToken cancellationToken = default(CancellationToken));
}


The client now simplified to its core features.

The commonly used parameters can be aggregated into a class

public class RestRequest {

    public RestRequest() {
    }

    public RestRequest(IRestClient client) : this() {
        var contentType = client.DefaultContentType;
        if (!string.IsNullOrEmpty(contentType)) {
            ContentType = contentType;
        }
        var headers = client.DefaultRequestHeaders;
        if (headers != null) {
            foreach (var header in headers) {
                Headers.Add(header.Key, header.Value);
            }
        }
    }

    public IRestHeadersCollection Headers { get; } = new RestRequestHeaders();

    public Uri Resource { get; set; }
    public HttpVerb HttpVerb { get; set; } = HttpVerb.Get;
    public string ContentType { get; set; } = "application/json";
    public object Body { get; set; }

    class RestRequestHeaders : HttpHeaders, IRestHeadersCollection {
        public RestRequestHeaders() : base() { }
        public IEnumerable&lt;string&gt; this[string name] =&gt; GetValues(name) ?? Array.Empty&lt;string&gt;();
    }
}


Naming is important here. Change the name to resource from queryString, which means something different to how it was originally being used with regards to HTTP requests.

Parameter order should also be changed to be more consistent.

Your original call would have looked something like

...await client.PostAsync&lt;ReturnObject, BodyObject&gt;(body, "...");


with the URI parameter second. When making the request, the first argument should be the resource being called. Everything else can be built up from there

...await client.PostAsync&lt;ReturnObject, BodyObject&gt;("...", body);
...await client.PostAsync&lt;ReturnObject, BodyObject&gt;("...", body, token);
//...etc


The following extensions allow for the same functionality as before on the IRestClient abstraction

public static class RestClientExtensions {
    #region Delete
    public static Task DeleteAsync(this IRestClient client, string resource) {
        return client.DeleteAsync(new Uri(resource, UriKind.Relative));
    }

    public static Task DeleteAsync(this IRestClient client, Uri resource) {
        return client.DeleteAsync(resource, CancellationToken.None);
    }

    public static Task DeleteAsync(this IRestClient client, Uri resource, CancellationToken cancellationToken) {
        var request = new RestRequest(client) {
            Resource = resource,
            HttpVerb = HttpVerb.Delete
        };
        return client.SendAsync&lt;object&gt;(request, cancellationToken);
    }
    #endregion

    #region Get
    public static Task&lt;RestResponse&lt;TReturn&gt;&gt; GetAsync&lt;TReturn&gt;(this IRestClient client) {
        var request = new RestRequest(client) {
            HttpVerb = HttpVerb.Get
        };
        return client.SendAsync&lt;TReturn&gt;(request, CancellationToken.None);
    }

    public static Task&lt;RestResponse&lt;TResult&gt;&gt; GetAsync&lt;TResult&gt;(this IRestClient client, string resource) {
        try {
            return client.GetAsync&lt;TResult&gt;(new Uri(resource, UriKind.Relative));
        } catch (UriFormatException ufe) {
            if (ufe.Message == "A relative URI cannot be created because the 'uriString' parameter represents an absolute URI.") {
                throw new UriFormatException(Messages.ErrorMessageAbsoluteUriAsString, ufe);
            }
            throw;
        }
    }

    public static Task&lt;RestResponse&lt;TReturn&gt;&gt; GetAsync&lt;TReturn&gt;(this IRestClient client, Uri resource) {
        return client.GetAsync&lt;TReturn&gt;(resource, CancellationToken.None);
    }

    public static Task&lt;RestResponse&lt;TReturn&gt;&gt; GetAsync&lt;TReturn&gt;(this IRestClient client, Uri resource, CancellationToken cancellationToken) {
        var request = new RestRequest(client) {
            Resource = resource
        };
        return client.SendAsync&lt;TReturn&gt;(request, cancellationToken);
    }
    #endregion

    #region Patch
    public static Task&lt;RestResponse&lt;TReturn&gt;&gt; PatchAsync&lt;TReturn, TBody&gt;(this IRestClient client, Uri resource, TBody body) {
        return client.PatchAsync&lt;TReturn, TBody&gt;(resource, body, CancellationToken.None);
    }

    public static Task&lt;RestResponse&lt;TReturn&gt;&gt; PatchAsync&lt;TReturn, TBody&gt;(this IRestClient client, Uri resource, TBody body, CancellationToken cancellationToken) {
        var request = new RestRequest(client) {
            Resource = resource,
            HttpVerb = HttpVerb.Patch,
            Body = body,
        };
        return client.SendAsync&lt;TReturn&gt;(request, cancellationToken);
    }
    #endregion

    #region Post
    public static Task&lt;RestResponse&lt;TReturn&gt;&gt; PostAsync&lt;TReturn, TBody&gt;(this IRestClient client, TBody body, Uri querresourceString) {
        return client.PostAsync&lt;TReturn, TBody&gt;(body, querresourceString, CancellationToken.None);
    }

    public static Task&lt;RestResponse&lt;TReturn&gt;&gt; PostAsync&lt;TReturn, TBody&gt;(this IRestClient client, TBody body, Uri resource, CancellationToken cancellationToken) {
        var request = new RestRequest(client) {
            Resource = resource,
            HttpVerb = HttpVerb.Post,
            Body = body,
        };
        return client.SendAsync&lt;TReturn&gt;(request, cancellationToken);
    }
    #endregion

    #region Put
    public static Task&lt;RestResponse&lt;TReturn&gt;&gt; PutAsync&lt;TReturn, TBody&gt;(this IRestClient client, TBody body, Uri resource) {
        return client.PutAsync&lt;TReturn, TBody&gt;(body, resource, CancellationToken.None);
    }

    public static Task&lt;RestResponse&lt;TReturn&gt;&gt; PutAsync&lt;TReturn, TBody&gt;(this IRestClient client, TBody body, Uri resource, CancellationToken cancellationToken) {
        var request = new RestRequest(client) {
            Resource = resource,
            HttpVerb = HttpVerb.Put,
            Body = body,
        };
        return client.SendAsync&lt;TReturn&gt;(request, cancellationToken);
    }
    #endregion
}