C
C#2y ago
HimmDawg

Generic api base client

I'm trying to implement a generic api base client using Polly and System.Net.Http.Formatting. I have this GetAsync<T>(string url) function here
public async Task<RestResponse<T>> GetAsync<T>(string url)
{
var response = await _retryPolicy.ExecuteAsync(async () => await _httpClient.GetAsync(url));

if (!response.IsSuccessStatusCode)
{
throw new Exception($"Failed to call API endpoint. Status code: {response.StatusCode}");
}

//var content = await response.Content.ReadAsByteArrayAsync();
var content2 = await response.Content.ReadAsAsync<T>();
return new RestResponse<T>(response.StatusCode, content2);
}
public async Task<RestResponse<T>> GetAsync<T>(string url)
{
var response = await _retryPolicy.ExecuteAsync(async () => await _httpClient.GetAsync(url));

if (!response.IsSuccessStatusCode)
{
throw new Exception($"Failed to call API endpoint. Status code: {response.StatusCode}");
}

//var content = await response.Content.ReadAsByteArrayAsync();
var content2 = await response.Content.ReadAsAsync<T>();
return new RestResponse<T>(response.StatusCode, content2);
}
RestResponse just encapsulates the data and the statuscode and _retryPolicy is an IAsyncPolicy from Polly.
public class RestResponse<T>
{
public RestResponse(HttpStatusCode statusCode, T data)
{
StatusCode = statusCode;
Data = data;
}

public HttpStatusCode StatusCode { get; set; }

public T Data { get; set; }
}
public class RestResponse<T>
{
public RestResponse(HttpStatusCode statusCode, T data)
{
StatusCode = statusCode;
Data = data;
}

public HttpStatusCode StatusCode { get; set; }

public T Data { get; set; }
}
Now the question is: Could I somehow use this function when T is byte[]? If I do that in the current state, then I get an error, that the media type of the response data is application/pdf and no MediaTypeFormatter exists for that.
1 Reply
HimmDawg
HimmDawgOP2y ago
Ok, I stumbled upon a solution. ReadAsAsync<T> has an overload that accepts an IEnumerable<MediaTypeFormatters> and an IFormatterLogger. Then I wrote a custom media type formatter for byte[]
public class ByteArrayMediaTypeFormatter : MediaTypeFormatter
{
public ByteArrayMediaTypeFormatter()
{
base.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/pdf"));
}

public override bool CanReadType(Type type)
{
if (type == typeof(byte[]))
{
return true;
}

return false;
}

public override bool CanWriteType(Type type)
{
if (type == typeof(byte[]))
{
return true;
}

return false;
}

public async override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
{
if (value is byte[] bytes)
{
await writeStream.WriteAsync(bytes, 0, bytes.Length);
}
else
{
throw new ArgumentException($"Cannot serialize type for {nameof(value)}");
}
}

public async override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
{
return await content.ReadAsByteArrayAsync();
}
}
public class ByteArrayMediaTypeFormatter : MediaTypeFormatter
{
public ByteArrayMediaTypeFormatter()
{
base.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/pdf"));
}

public override bool CanReadType(Type type)
{
if (type == typeof(byte[]))
{
return true;
}

return false;
}

public override bool CanWriteType(Type type)
{
if (type == typeof(byte[]))
{
return true;
}

return false;
}

public async override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
{
if (value is byte[] bytes)
{
await writeStream.WriteAsync(bytes, 0, bytes.Length);
}
else
{
throw new ArgumentException($"Cannot serialize type for {nameof(value)}");
}
}

public async override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
{
return await content.ReadAsByteArrayAsync();
}
}
And that gives me the exact bytes as with ReadAsByteArrayAsync()
Want results from more Discord servers?
Add your server