Created
November 26, 2014 19:21
-
-
Save josh-cooley/b19ad7dc60a462b4ecff to your computer and use it in GitHub Desktop.
BruTile RequestHelper with async fetch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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