Skip to content

Instantly share code, notes, and snippets.

@josh-cooley
Created November 26, 2014 19:21
Show Gist options
  • Save josh-cooley/b19ad7dc60a462b4ecff to your computer and use it in GitHub Desktop.
Save josh-cooley/b19ad7dc60a462b4ecff to your computer and use it in GitHub Desktop.
BruTile RequestHelper with async fetch
using BruTile.Web;
using System;
using System.Globalization;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace AsyncRequestHelper
{
public static class RequestHelper
{
static RequestHelper()
{
Timeout = 10000;
}
public static int Timeout { get; set; }
public static ICredentials Credentials { get; set; }
public static async Task<byte[]> FetchImage(Uri uri)
{
CancellationTokenSource fetchCancelSource = new CancellationTokenSource();
var fetchTask = FetchImageCore(uri, fetchCancelSource.Token);
if (fetchTask.IsCompleted || Timeout == System.Threading.Timeout.Infinite)
{
// Either the task has already completed or timeout will never occur.
// No proxy necessary.
return await fetchTask;
}
CancellationTokenSource delayCancelSource = new CancellationTokenSource();
var timeoutTask = Task.Delay(Timeout, delayCancelSource.Token);
var completedTask = await Task.WhenAny(fetchTask, timeoutTask);
if (completedTask == fetchTask)
{
delayCancelSource.Cancel();
return await fetchTask;
}
else
{
fetchCancelSource.Cancel();
throw new TimeoutException("No response received in time.");
}
}
private static async Task<byte[]> FetchImageCore(Uri uri, CancellationToken cancellationToken)
{
using (var handler = new HttpClientHandler { Credentials = Credentials })
using (var client = new HttpClient(handler))
{
var response = await client.GetAsync(uri, cancellationToken);
var bytes = await response.Content.ReadAsByteArrayAsync();
if (response.Content.Headers.ContentType.MediaType.StartsWith("image", StringComparison.OrdinalIgnoreCase))
{
return bytes;
}
throw new WebResponseFormatException(ComposeErrorMessage(response, bytes, response.RequestMessage.RequestUri.AbsoluteUri));
}
}
private static string ComposeErrorMessage(HttpResponseMessage httpResponse, byte[] bytes, string uri)
{
string message = String.Format(
CultureInfo.InvariantCulture,
"Failed to retrieve tile from this uri:\n{0}\n.An image was expected but the received type was '{1}'.",
uri,
httpResponse.Content.Headers.ContentType
);
if (httpResponse.Content.Headers.ContentType.MediaType.StartsWith("text", StringComparison.OrdinalIgnoreCase))
{
using (var stream = new MemoryStream(bytes))
{
message += String.Format(CultureInfo.InvariantCulture,
"\nThis was returned:\n{0}", ReadAllText(stream));
}
}
return message;
}
private static string ReadAllText(Stream responseStream)
{
using (var streamReader = new StreamReader(responseStream, true))
{
using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture))
{
stringWriter.Write(streamReader.ReadToEnd());
return stringWriter.ToString();
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment