/// <summary> /// Queries ESI to send a request. /// </summary> /// <typeparam name="T">The type of the response.</typeparam> /// <param name="method">The HTTP method to use when making the request.</param> /// <param name="request">The ESI request to make.</param> /// <param name="content">The content to send with the request.</param> /// <returns>The data from the ESI request.</returns> private async Task <EsiResult <T> > QueryEsiAsync <T>(HttpMethod method, EsiRequestHeaders request, HttpContent content = null) { string url = await request.GetESIUrlAsync(Language).ConfigureAwait(false); var message = new HttpRequestMessage(method, url); if (content != null) { // Update content type if requested string contentType = request.ContentType.GetAttributeOfType < DescriptionAttribute>()?.Description; if (contentType != null && content.Headers != null) { content.Headers.ContentType.MediaType = contentType; } message.Content = content; } EsiResult <T> esiResult; // If previous request expiration is available, add ETag/If-Modified-Since request.CacheInfo?.AddRequestHeaders(message.Headers); try { using (var response = await client.SendAsync(message).ConfigureAwait(false)) { esiResult = await HandleResponseAsync <T>(response); } } catch (IOException e) { // I/O errors become EsiResultStatus.NetworkError esiResult = new EsiResult <T>(EsiResultStatus.NetworkError, default(T), e); } catch (TimeoutException e) { // Time outs become EsiResultStatus.NetworkError esiResult = new EsiResult <T>(EsiResultStatus.NetworkError, default(T), e); } catch (OperationCanceledException e) { // Cancellations become EsiResultStatus.NetworkError esiResult = new EsiResult <T>(EsiResultStatus.NetworkError, default(T), e); } return(esiResult); }
/// <summary> /// Handles a response from ESI. /// </summary> /// <typeparam name="T">The type of the response.</typeparam> /// <param name="response">The response message from the server.</param> /// <returns>The data from the ESI request.</returns> private async Task <EsiResult <T> > HandleResponseAsync <T>(HttpResponseMessage response) { var headers = response.Headers; var received = DateTime.UtcNow; EsiResult <T> result; headers.ThrowIfNull(nameof(headers)); // Update error count int?ec = GetIntParam(headers, "X-Esi-Error-Limit-Remain"); if (ec != null) { errorCount = (int)ec; } // Update error count refresh time, no more than 2 minutes in the future int?ecReset = GetIntParam(headers, "X-Esi-Error-Limit-Reset"); if (ecReset != null) { errorCountRefresh = received.AddSeconds(Math.Min((int)ecReset, 120)); } var status = ToEsiStatusCode(response.StatusCode); int pages = GetIntParam(headers, "X-Pages") ?? 0; if (pages < 1) { pages = 1; } if (status == EsiResultStatus.OK) { try { // Parse the ESI payload, content should not be null if response was OK var serializer = new JsonSerializer { DateTimeZoneHandling = DateTimeZoneHandling.Utc }; var content = response.Content; content.ThrowIfNull(nameof(content)); using (var jr = new JsonTextReader(new StreamReader(await content. ReadAsStreamAsync(), Encoding.UTF8))) { jr.CloseInput = true; // JSON parsing result = new EsiResult <T>(status, serializer.Deserialize <T>(jr)) { CacheInfo = new EsiCacheInfo(headers.ETag?.Tag, content.Headers. Expires?.UtcDateTime ?? received), Pages = pages }; // Determine date and time on the server, no more laggy NIST time sync var serverDate = headers.Date; if (serverDate != null) { result.ServerTime = ((DateTimeOffset)serverDate).UtcDateTime; } jr.Close(); } } catch (JsonException e) { // JSON parse failures become EsiResultStatus.Error result = new EsiResult <T>(EsiResultStatus.Error, default(T), e); } } else { result = new EsiResult <T>(status); } return(result); }