Func <HttpClient, object[], Task> BuildVoidTaskFuncForMethod(RestMethodInfo restMethod)
        {
            return(async(client, paramList) => {
                if (client.BaseAddress == null)
                {
                    throw new InvalidOperationException("BaseAddress must be set on the HttpClient instance");
                }

                var factory = BuildRequestFactoryForMethod(restMethod.Name, client.BaseAddress.AbsolutePath, restMethod.CancellationToken != null);
                var rq = factory(paramList);

                var ct = CancellationToken.None;

                if (restMethod.CancellationToken != null)
                {
                    ct = paramList.OfType <CancellationToken>().FirstOrDefault();
                }

                using (var resp = await client.SendAsync(rq, ct).ConfigureAwait(false)) {
                    if (!resp.IsSuccessStatusCode)
                    {
                        throw await ApiException.Create(rq.RequestUri, restMethod.HttpMethod, resp, settings).ConfigureAwait(false);
                    }
                }
            });
        }
        Func <HttpClient, object[], Task <T> > buildTaskFuncForMethod <T>(RestMethodInfo restMethod)
            where T : class
        {
            return(async(client, paramList) => {
                var factory = BuildRequestFactoryForMethod(restMethod.Name, client.BaseAddress.AbsolutePath);
                var rq = factory(paramList);
                var resp = await client.SendAsync(rq);

                if (restMethod.SerializedReturnType == typeof(HttpResponseMessage))
                {
                    return resp as T;
                }

                if (!resp.IsSuccessStatusCode)
                {
                    throw await ApiException.Create(resp);
                }

                var content = await resp.Content.ReadAsStringAsync();

                if (restMethod.SerializedReturnType == typeof(string))
                {
                    return content as T;
                }

                return JsonConvert.DeserializeObject <T>(content);
            });
        }
Example #3
0
        Func <HttpClient, CancellationToken, object[], Task <T> > buildCancellableTaskFuncForMethod <T>(RestMethodInfo restMethod)
            where T : class
        {
            return(async(client, ct, paramList) => {
                var factory = BuildRequestFactoryForMethod(restMethod.Name, client.BaseAddress.AbsolutePath);
                var rq = factory(paramList);

                var resp = await client.SendAsync(rq, HttpCompletionOption.ResponseHeadersRead, ct);

                if (restMethod.SerializedReturnType == typeof(HttpResponseMessage))
                {
                    return resp as T;
                }

                if (!resp.IsSuccessStatusCode)
                {
                    throw await ApiException.Create(resp);
                }

                var ms = new MemoryStream();
                var fromStream = await resp.Content.ReadAsStreamAsync();

                await fromStream.CopyToAsync(ms, 4096, ct);

                var bytes = ms.ToArray();
                var content = Encoding.UTF8.GetString(bytes, 0, bytes.Length);
                if (restMethod.SerializedReturnType == typeof(string))
                {
                    return content as T;
                }

                return JsonConvert.DeserializeObject <T>(content);
            });
        }
Example #4
0
        Func <HttpClient, object[], Task> buildVoidTaskFuncForMethod(RestMethodInfo restMethod)
        {
            return(async(client, paramList) => {
                var factory = BuildRequestFactoryForMethod(restMethod.Name, client.BaseAddress.AbsolutePath);
                var rq = factory(paramList);
                var resp = await client.SendAsync(rq);

                if (!resp.IsSuccessStatusCode)
                {
                    throw await ApiException.Create(resp, settings);
                }
            });
        }
Example #5
0
        Func <HttpClient, CancellationToken, object[], Task <T> > BuildCancellableTaskFuncForMethod <T>(RestMethodInfo restMethod)
        {
            return(async(client, ct, paramList) => {
                if (client.BaseAddress == null)
                {
                    throw new InvalidOperationException("BaseAddress must be set on the HttpClient instance");
                }

                var factory = BuildRequestFactoryForMethod(restMethod.Name, client.BaseAddress.AbsolutePath, restMethod.CancellationToken != null);
                var rq = factory(paramList);

                var resp = await client.SendAsync(rq, HttpCompletionOption.ResponseHeadersRead, ct).ConfigureAwait(false);

                if (restMethod.SerializedReturnType == typeof(HttpResponseMessage))
                {
                    // NB: This double-casting manual-boxing hate crime is the only way to make
                    // this work without a 'class' generic constraint. It could blow up at runtime
                    // and would be A Bad Idea if we hadn't already vetted the return type.
                    return (T)(object)resp;
                }

                if (!resp.IsSuccessStatusCode)
                {
                    throw await ApiException.Create(rq.RequestUri, restMethod.HttpMethod, resp, restMethod.RefitSettings).ConfigureAwait(false);
                }

                if (restMethod.SerializedReturnType == typeof(HttpContent))
                {
                    return (T)(object)resp.Content;
                }

                if (restMethod.SerializedReturnType == typeof(Stream))
                {
                    return (T)(object)await resp.Content.ReadAsStreamAsync().ConfigureAwait(false);
                }

                using (var stream = await resp.Content.ReadAsStreamAsync().ConfigureAwait(false))
                    using (var reader = new StreamReader(stream)) {
                        if (restMethod.SerializedReturnType == typeof(string))
                        {
                            return (T)(object)await reader.ReadToEndAsync().ConfigureAwait(false);
                        }

                        using (var jsonReader = new JsonTextReader(reader)) {
                            return serializer.Deserialize <T>(jsonReader);
                        }
                    }
            });
        }
Example #6
0
        Func <HttpClient, CancellationToken, object[], Task <T> > BuildCancellableTaskFuncForMethod <T>(RestMethodInfo restMethod)
        {
            return(async(client, ct, paramList) => {
                var factory = BuildRequestFactoryForMethod(restMethod.Name, client.BaseAddress.AbsolutePath, restMethod.CancellationToken != null);
                var rq = factory(paramList);

                var resp = await client.SendAsync(rq, HttpCompletionOption.ResponseHeadersRead, ct).ConfigureAwait(false);

                if (restMethod.SerializedReturnType == typeof(HttpResponseMessage))
                {
                    // NB: This double-casting manual-boxing hate crime is the only way to make
                    // this work without a 'class' generic constraint. It could blow up at runtime
                    // and would be A Bad Idea if we hadn't already vetted the return type.
                    return (T)(object)resp;
                }

                if (!resp.IsSuccessStatusCode)
                {
                    throw await ApiException.Create(rq.RequestUri, restMethod.HttpMethod, resp, restMethod.RefitSettings).ConfigureAwait(false);
                }

                if (restMethod.SerializedReturnType == typeof(HttpContent))
                {
                    return (T)(object)resp.Content;
                }

                var content = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);

                if (restMethod.SerializedReturnType == typeof(string))
                {
                    return (T)(object)content;
                }

                var deserializedObject = JsonConvert.DeserializeObject <T>(content, settings.JsonSerializerSettings);

                // enable message post-processor functionality on resulting object if implements interface,
                // so it is possible to access http response message even when resulting type
                // of the call is something more specific (e.g. to allow processing of response headers)
                if (deserializedObject is IHttpResponseMessagePostProcessor)
                {
                    (deserializedObject as IHttpResponseMessagePostProcessor).PostProcessHttpResponseMessage(resp);
                }

                return deserializedObject;
            });
        }
        Func <HttpClient, CancellationToken, object[], Task <T> > buildCancellableTaskFuncForMethod <T>(RestMethodInfo restMethod)
        {
            return(async(client, ct, paramList) => {
                var factory = buildRequestFactoryForMethod(restMethod.Name, client.BaseAddress.AbsolutePath, restMethod.CancellationToken != null);
                var rq = factory(paramList);

                var resp = await client.SendAsync(rq, HttpCompletionOption.ResponseHeadersRead, ct).ConfigureAwait(false);

                if (restMethod.SerializedReturnType == typeof(HttpResponseMessage))
                {
                    // NB: This double-casting manual-boxing hate crime is the only way to make
                    // this work without a 'class' generic constraint. It could blow up at runtime
                    // and would be A Bad Idea if we hadn't already vetted the return type.
                    return (T)(object)resp;
                }

                if (!resp.IsSuccessStatusCode)
                {
                    throw await ApiException.Create(rq.RequestUri, restMethod.HttpMethod, resp, restMethod.RefitSettings).ConfigureAwait(false);
                }

                if (restMethod.SerializedReturnType == typeof(HttpContent))
                {
                    return (T)(object)resp.Content;
                }

                var ms = new MemoryStream();
                using (var fromStream = await resp.Content.ReadAsStreamAsync().ConfigureAwait(false)) {
                    await fromStream.CopyToAsync(ms, 4096, ct).ConfigureAwait(false);
                }

                var bytes = ms.ToArray();
                var content = Encoding.UTF8.GetString(bytes, 0, bytes.Length);

                if (restMethod.SerializedReturnType == typeof(string))
                {
                    return (T)(object)content;
                }

                return JsonConvert.DeserializeObject <T>(content, settings.JsonSerializerSettings);
            });
        }
Example #8
0
        Func <HttpClient, CancellationToken, object[], Task <T> > BuildCancellableTaskFuncForMethod <T>(RestMethodInfo restMethod)
        {
            return(async(client, ct, paramList) =>
            {
                if (client.BaseAddress == null)
                {
                    throw new InvalidOperationException("BaseAddress must be set on the HttpClient instance");
                }

                var factory = BuildRequestFactoryForMethod(restMethod, client.BaseAddress.AbsolutePath, restMethod.CancellationToken != null);
                var rq = factory(paramList);
                HttpResponseMessage resp = null;
                var disposeResponse = true;
                try
                {
                    resp = await client.SendAsync(rq, HttpCompletionOption.ResponseHeadersRead, ct).ConfigureAwait(false);

                    if (restMethod.SerializedReturnType == typeof(HttpResponseMessage))
                    {
                        disposeResponse = false; // caller has to dispose

                        // NB: This double-casting manual-boxing hate crime is the only way to make
                        // this work without a 'class' generic constraint. It could blow up at runtime
                        // and would be A Bad Idea if we hadn't already vetted the return type.
                        return (T)(object)resp;
                    }

                    var isApiResponse = restMethod.SerializedReturnType.GetTypeInfo().IsGenericType&&
                                        restMethod.SerializedReturnType.GetGenericTypeDefinition() == typeof(ApiResponse <>);

                    if (!resp.IsSuccessStatusCode && !isApiResponse)
                    {
                        disposeResponse = false;
                        throw await ApiException.Create(rq, restMethod.HttpMethod, resp, restMethod.RefitSettings).ConfigureAwait(false);
                    }

                    var serializedReturnType = (isApiResponse) ? restMethod.SerializedGenericArgument : restMethod.SerializedReturnType;

                    if (serializedReturnType == typeof(HttpContent))
                    {
                        disposeResponse = false; // caller has to clean up the content
                        if (isApiResponse)
                        {
                            return ApiResponse.Create <T>(resp, resp.Content);
                        }
                        return (T)(object)resp.Content;
                    }

                    if (serializedReturnType == typeof(Stream))
                    {
                        disposeResponse = false; // caller has to dispose
                        var stream = (object)await resp.Content.ReadAsStreamAsync().ConfigureAwait(false);

                        if (isApiResponse)
                        {
                            return ApiResponse.Create <T>(resp, stream);
                        }
                        return (T)stream;
                    }

                    using (var stream = await resp.Content.ReadAsStreamAsync().ConfigureAwait(false))
                        using (var reader = new StreamReader(stream))
                        {
                            if (serializedReturnType == typeof(string))
                            {
                                var str = (object)await reader.ReadToEndAsync().ConfigureAwait(false);

                                if (isApiResponse)
                                {
                                    return ApiResponse.Create <T>(resp, str);
                                }
                                return (T)str;
                            }

                            using (var jsonReader = new JsonTextReader(reader))
                            {
                                var json = serializer.Deserialize(jsonReader, serializedReturnType);
                                if (isApiResponse)
                                {
                                    return ApiResponse.Create <T>(resp, json);
                                }
                                return (T)json;
                            }
                        }
                }
                finally
                {
                    // Ensure we clean up the request
                    // Especially important if it has open files/streams
                    rq.Dispose();
                    if (disposeResponse)
                    {
                        resp?.Dispose();
                    }
                }
            });
        }
        Func <HttpClient, CancellationToken, object[], Task <T> > BuildCancellableTaskFuncForMethod <T, TBody>(RestMethodInfo restMethod)
        {
            return(async(client, ct, paramList) =>
            {
                if (client.BaseAddress == null)
                {
                    throw new InvalidOperationException("BaseAddress must be set on the HttpClient instance");
                }

                var factory = BuildRequestFactoryForMethod(restMethod, client.BaseAddress.AbsolutePath, restMethod.CancellationToken != null);
                var rq = await factory(paramList).ConfigureAwait(false);

                HttpResponseMessage resp = null;
                HttpContent content = null;
                var disposeResponse = true;
                try
                {
                    resp = await client.SendAsync(rq, HttpCompletionOption.ResponseHeadersRead, ct).ConfigureAwait(false);

                    content = resp.Content ?? new StringContent(string.Empty);

                    if (restMethod.SerializedReturnType == typeof(HttpResponseMessage))
                    {
                        disposeResponse = false; // caller has to dispose

                        // NB: This double-casting manual-boxing hate crime is the only way to make
                        // this work without a 'class' generic constraint. It could blow up at runtime
                        // and would be A Bad Idea if we hadn't already vetted the return type.
                        return (T)(object)resp;
                    }

                    if (!resp.IsSuccessStatusCode)
                    {
                        disposeResponse = false;

                        var exception = await ApiException.Create(rq, restMethod.HttpMethod, resp, restMethod.RefitSettings).ConfigureAwait(false);

                        if (restMethod.IsApiResponse)
                        {
                            return ApiResponse.Create <T>(resp, default(T), exception);
                        }

                        throw exception;
                    }

                    var serializedReturnType = restMethod.IsApiResponse ? restMethod.SerializedGenericArgument : restMethod.SerializedReturnType;

                    if (serializedReturnType == typeof(HttpContent))
                    {
                        disposeResponse = false; // caller has to clean up the content
                        if (restMethod.IsApiResponse)
                        {
                            return ApiResponse.Create <T>(resp, content);
                        }
                        return (T)(object)content;
                    }

                    if (serializedReturnType == typeof(Stream))
                    {
                        disposeResponse = false; // caller has to dispose
                        var stream = (object)await content.ReadAsStreamAsync().ConfigureAwait(false);

                        if (restMethod.IsApiResponse)
                        {
                            return ApiResponse.Create <T>(resp, stream);
                        }
                        return (T)stream;
                    }

                    if (serializedReturnType == typeof(string))
                    {
                        using (var stream = await content.ReadAsStreamAsync().ConfigureAwait(false))
                            using (var reader = new StreamReader(stream))
                            {
                                var str = (object)await reader.ReadToEndAsync().ConfigureAwait(false);

                                if (restMethod.IsApiResponse)
                                {
                                    return ApiResponse.Create <T>(resp, str);
                                }
                                return (T)str;
                            }
                    }

                    var body = await serializer.DeserializeAsync <TBody>(content);

                    if (restMethod.IsApiResponse)
                    {
                        return ApiResponse.Create <T>(resp, body);
                    }

                    //  Unfortunate side-effect of having no 'class' or 'T : TBody' constraints.
                    //  However, we know that T must be the same as TBody because IsApiResponse != true so
                    //  this code is safe at runtime.
                    return (T)(object)body;
                }
                finally
                {
                    // Ensure we clean up the request
                    // Especially important if it has open files/streams
                    rq.Dispose();
                    if (disposeResponse)
                    {
                        resp?.Dispose();
                        content?.Dispose();
                    }
                }
            });
        }