Skip to content

Instantly share code, notes, and snippets.

@ian-beer
Last active March 26, 2021 10:34
Show Gist options
  • Save ian-beer/6247d20642e789db211c3def6624c5bc to your computer and use it in GitHub Desktop.
Save ian-beer/6247d20642e789db211c3def6624c5bc to your computer and use it in GitHub Desktop.
.Net RestClient
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Net.Http.Headers;
using Newtonsoft.Json.Linq;
namespace HttpUtils
{
public static class RestClient
{
public static async Task<HttpResponseMessage> Get(string url, IDictionary<string, string> headers)
{
return await Send(BuildRequestMessage(HttpMethod.Get, url, headers));
}
public static async Task<HttpResponseMessage> Post(string url, IDictionary<string, string> headers)
{
return await Send(BuildRequestMessage(HttpMethod.Post, url, headers));
}
public static async Task<HttpResponseMessage> Post(string url, IDictionary<string, string> headers, string content)
{
return await Send(BuildRequestMessage(HttpMethod.Post, url, headers, content));
}
private static async Task<HttpResponseMessage> Send(HttpRequestMessage request)
{
using (var client = new HttpClient())
{
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
return response;
}
var responseContent = await response.Content.ReadAsStringAsync();
throw new HttpRequestException($"error occured in RestClient when calling: request: {request.RequestUri} statusCode: {response.StatusCode}", new Exception(responseContent));
}
}
private static HttpRequestMessage BuildRequestMessage(HttpMethod method, string url,
IDictionary<string, string> headers, string jsonString = null)
{
var request = new HttpRequestMessage
{
RequestUri = new Uri(url),
Method = method,
};
foreach (var header in headers)
{
request.Headers.Add(header.Key, header.Value);
}
if (jsonString != null)
{
request.Content = new StringContent(jsonString);
}
return request;
}
}
public static class HttpUtils
{
public static JObject FormDataToJson(this NameValueCollection data)
{
var json = new JObject();
for (var i = 0; i < data.Count; i++)
{
var key = data.GetKey(i);
var value = data.GetValues(key);
json.Add(key, value?[0]);
}
return json;
}
public static KeyValuePair<string, string> BuildXAuthHeader(string authToken)
{
return new KeyValuePair<string, string>("X-Auth-Token", authToken);
}
public static KeyValuePair<string, string> BuildBasicAuthHeader(string username, string password)
{
var encodedCredentials = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{username}:{password}"));
return new KeyValuePair<string, string>("Authorization", $"Basic {encodedCredentials}");
}
public static IDictionary<string, string> BuildXAuthHeaderDictionary(string authToken)
{
var authHeader = BuildXAuthHeader(authToken);
return new Dictionary<string, string> { { authHeader.Key, authHeader.Value } };
}
public static IDictionary<string, string> BuildBasicAuthHeaderDictionary(string username, string password)
{
var authHeader = BuildBasicAuthHeader(username, password);
return new Dictionary<string, string> { { authHeader.Key, authHeader.Value } };
}
/// <summary>
/// Check the Link header for a rel='next' ini. If present return ini link.
/// </summary>
/// <param name="headers"></param>
/// <returns></returns>
public static string GetNextResource(HttpResponseHeaders headers)
{
var linkHeader = headers.SingleOrDefault(h => h.Key.ToLowerInvariant() == "link");
if (linkHeader.Key == null)
{
return null;
}
var linkHeaderDictionary = ParseLinkHeader(linkHeader.Value.SingleOrDefault());
return linkHeaderDictionary.ContainsKey("rel='next'") ? linkHeaderDictionary["rel='next'"] : null;
}
/// <summary>
/// The link header contains related iris for deep crawl api
/// ex:
/// { </accounts/41358/projects/263913/crawls/1882279/reports?page=1&per_page=200&sort=id>; rel='first',
/// </accounts/41358/projects/263913/crawls/1882279/reports?page=2&per_page=200&sort=id>; rel='last',
/// </accounts/41358/projects/263913/crawls/1882279/reports?page=2&per_page=200&sort=id>; rel='next' }
///
/// because of pagination we need to parse this data for the 'next' iri.
///
/// see: https://tools.ietf.org/html/rfc3987, https://tools.ietf.org/html/rfc5988#page-6
/// </summary>
/// <param name="headerValue"></param>
/// <returns></returns>
public static Dictionary<string,string> ParseLinkHeader(string headerValue)
{
return headerValue.Split(',').ToDictionary(l =>
{
var iniSplit = l.Split(';');
return iniSplit[1].Trim();
}, l =>
{
var iniSplit = l.Split(';');
var link = iniSplit[0].Trim();
var cleanLink = link.Trim('<', '>');
return cleanLink;
});
}
/// <summary>
/// Use this if your url or injectable partial of a url may contain special characters
/// NOTE: this was made for an Azure Function. Utilizes the wrong library for .Net web apps.
/// see: https://docs.microsoft.com/en-us/dotnet/api/system.web.httputility.urlencode?view=netframework-4.6.1
/// </summary>
/// <param name="urlOrPartial">full Url or any partial of an url</param>
/// <returns></returns>
public static string EncodeUrlOrPartial(string urlOrPartial)
{
return System.Net.WebUtility.HtmlEncode(urlOrPartial);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment