Skip to content

Instantly share code, notes, and snippets.

@kofifus
Created August 23, 2021 02:47
Show Gist options
  • Save kofifus/9360bdf9d98925c2e6ab6ccba4fa18ad to your computer and use it in GitHub Desktop.
Save kofifus/9360bdf9d98925c2e6ab6ccba4fa18ad to your computer and use it in GitHub Desktop.
HttpFile GetToFileAsync, GetToStringAsync, PostToStringAsync
namespace System.Net.Http {
// holds the non disposable parts of HttpResponseMessage
public record HttpResponseInfo(HttpResponseHeaders Headers, bool IsSuccessStatusCode, string? ReasonPhrase, HttpStatusCode HttpStatusCode, HttpResponseHeaders TrailingHeaders, Version Version);
// holds Http exception information
public record HttpExceptionInfo(string ErrorMessage, WebExceptionStatus? WebExceptionStatus);
public record HttpResponse {
public HttpResponseInfo? HttpResponseInfo { get; init; }
public HttpExceptionInfo? HttpExceptionInfo { get; init; }
public HttpResponse(HttpResponseInfo? httpResponseInfo, HttpExceptionInfo? httpExceptionInfo = null) => (HttpResponseInfo, HttpExceptionInfo) = (httpResponseInfo, httpExceptionInfo);
public HttpResponse(Exception exception) {
HttpResponseInfo = null;
if (exception is WebException ex1 && ex1.Status == WebExceptionStatus.ProtocolError) {
using HttpWebResponse? httpResponse = (HttpWebResponse?)ex1.Response;
HttpExceptionInfo = new(httpResponse?.StatusDescription ?? "", ex1.Status);
}
else if (exception is WebException ex2) HttpExceptionInfo = new(ex2.FullMessage(), ex2.Status);
else if (exception is TaskCanceledException ex3 && ex3.InnerException is TimeoutException) HttpExceptionInfo = new(ex3.InnerException.FullMessage(), WebExceptionStatus.Timeout);
else if (exception is TaskCanceledException ex4) HttpExceptionInfo = new(ex4.FullMessage(), WebExceptionStatus.RequestCanceled);
else HttpExceptionInfo = new(exception.FullMessage(), null);
}
public override string ToString() {
if (HttpResponseInfo is object && HttpResponseInfo.IsSuccessStatusCode) {
var msg = "Success ";
msg += $" {Enum.GetName(typeof(HttpStatusCode), HttpResponseInfo.HttpStatusCode)}";
if (HttpResponseInfo.ReasonPhrase is object) msg += $" {HttpResponseInfo.ReasonPhrase}";
return msg;
} else {
var msg = "Failure";
if (HttpResponseInfo is object) {
msg += $" {Enum.GetName(typeof(HttpStatusCode), HttpResponseInfo.HttpStatusCode)}";
if (HttpResponseInfo.ReasonPhrase is object) msg += $" {HttpResponseInfo.ReasonPhrase}";
}
if (HttpExceptionInfo is object) {
msg += $" {HttpExceptionInfo.ErrorMessage}";
if (HttpExceptionInfo.WebExceptionStatus is object) msg += $" {Enum.GetName(typeof(WebExceptionStatus), HttpExceptionInfo.WebExceptionStatus)}";
}
return msg;
}
}
}
public static class ExtensionMethods {
public static async Task<(bool success, HttpResponse httpResponse)> GetToFileAsync(this HttpClient httpClient, Uri requestUri, string fileToWriteTo, CancellationTokenSource? cts = null, Action<long, int>? progressCallback = null) {
var created = false;
try {
var cancellationToken = cts?.Token ?? default;
using HttpResponseMessage responseMsg = await httpClient.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
var httpResponseInfo = new HttpResponseInfo(responseMsg.Headers, responseMsg.IsSuccessStatusCode, responseMsg.ReasonPhrase, responseMsg.StatusCode, responseMsg.TrailingHeaders, responseMsg.Version);
if (!responseMsg.IsSuccessStatusCode) return (false , new(httpResponseInfo));
var contentLength = responseMsg.Content.Headers.ContentLength;
using Stream streamToReadFrom = await responseMsg.Content.ReadAsStreamAsync();
using Stream streamToWriteTo = File.Open(fileToWriteTo, FileMode.Create);
created = true;
var bytesRecieved = (long)-1;
var progress = new Progress<long>(totalBytes => {
bytesRecieved = totalBytes;
if (progressCallback is null) return;
var percent = contentLength is object && contentLength != 0 ? (int)Math.Floor(totalBytes / (float)contentLength * 100.0) : -1;
progressCallback(totalBytes, percent);
});
await streamToReadFrom.CopyToAsync(streamToWriteTo, 81920, progress, cancellationToken);
return (true, new(httpResponseInfo));
}
catch (Exception ex) {
if (created) try { File.Delete(fileToWriteTo); } catch { };
return (false, new(ex));
}
}
public static async Task<(string? ResponseAsString, HttpResponse httpResponse)> GetToStringAsync(this HttpClient httpClient, Uri requestUri, CancellationTokenSource? cts = null) {
try {
var cancellationToken = cts?.Token ?? default;
using var responseMsg = await httpClient.GetAsync(requestUri, cancellationToken);
var httpResponseInfo = new HttpResponseInfo(responseMsg.Headers, responseMsg.IsSuccessStatusCode, responseMsg.ReasonPhrase, responseMsg.StatusCode, responseMsg.TrailingHeaders, responseMsg.Version);
if (!responseMsg.IsSuccessStatusCode) return (null, new(httpResponseInfo));
var responseAsString = await responseMsg.Content.ReadAsStringAsync();
return (responseAsString, new(httpResponseInfo));
}
catch (Exception ex) {
return (null, new(ex)); ;
}
}
public static async Task<(string? ResponseAsString, HttpResponse httpResponse)> PostToStringAsync(this HttpClient httpClient, Uri requestUri, HttpContent postBuffer, CancellationTokenSource? cts = null) {
try {
var cancellationToken = cts?.Token ?? default;
using var responseMsg = await httpClient.PostAsync(requestUri, postBuffer, cancellationToken);
var httpResponseInfo = new HttpResponseInfo(responseMsg.Headers, responseMsg.IsSuccessStatusCode, responseMsg.ReasonPhrase, responseMsg.StatusCode, responseMsg.TrailingHeaders, responseMsg.Version);
if (!responseMsg.IsSuccessStatusCode) return (null, new(httpResponseInfo));
var responseAsString = await responseMsg.Content.ReadAsStringAsync();
return (responseAsString, new(httpResponseInfo));
}
catch (Exception ex) {
return (null, new(ex));
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment