RaspberryIO_26/Swan/Net/JsonClient.cs

314 lines
15 KiB
C#
Raw Normal View History

2019-12-08 21:23:54 +01:00
#nullable enable
using Swan.Formatters;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Swan.Net {
/// <summary>
/// Represents a HttpClient with extended methods to use with JSON payloads
/// and bearer tokens authentication.
/// </summary>
public static class JsonClient {
private const String JsonMimeType = "application/json";
private const String FormType = "application/x-www-form-urlencoded";
private static readonly HttpClient HttpClient = new HttpClient();
2019-12-04 18:57:18 +01:00
/// <summary>
2019-12-08 21:23:54 +01:00
/// Post a object as JSON with optional authorization token.
2019-12-04 18:57:18 +01:00
/// </summary>
2019-12-08 21:23:54 +01:00
/// <typeparam name="T">The type of response object.</typeparam>
/// <param name="requestUri">The request URI.</param>
/// <param name="payload">The payload.</param>
/// <param name="authorization">The authorization.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// A task with a result of the requested type.
/// </returns>
public static async Task<T> Post<T>(Uri requestUri, Object payload, String? authorization = null, CancellationToken cancellationToken = default) where T : notnull {
String jsonString = await PostString(requestUri, payload, authorization, cancellationToken).ConfigureAwait(false);
return !String.IsNullOrEmpty(jsonString) ? Json.Deserialize<T>(jsonString) : default;
}
/// <summary>
/// Posts the specified URL.
/// </summary>
/// <param name="requestUri">The request URI.</param>
/// <param name="payload">The payload.</param>
/// <param name="authorization">The authorization.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// A task with a result as a collection of key/value pairs.
/// </returns>
public static async Task<IDictionary<String, Object>?> Post(Uri requestUri, Object payload, String? authorization = null, CancellationToken cancellationToken = default) {
String jsonString = await PostString(requestUri, payload, authorization, cancellationToken).ConfigureAwait(false);
return String.IsNullOrWhiteSpace(jsonString) ? default : Json.Deserialize(jsonString) as IDictionary<String, Object>;
}
/// <summary>
/// Posts the specified URL.
/// </summary>
/// <param name="requestUri">The request URI.</param>
/// <param name="payload">The payload.</param>
/// <param name="authorization">The authorization.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// A task with a result of the requested string.
/// </returns>
/// <exception cref="ArgumentNullException">url.</exception>
/// <exception cref="JsonRequestException">Error POST JSON.</exception>
public static Task<String> PostString(Uri requestUri, Object payload, String? authorization = null, CancellationToken cancellationToken = default) => SendAsync(HttpMethod.Post, requestUri, payload, authorization, cancellationToken);
/// <summary>
/// Puts the specified URL.
/// </summary>
/// <typeparam name="T">The type of response object.</typeparam>
/// <param name="requestUri">The request URI.</param>
/// <param name="payload">The payload.</param>
/// <param name="authorization">The authorization.</param>
/// <param name="ct">The cancellation token.</param>
/// <returns>
/// A task with a result of the requested type.
/// </returns>
public static async Task<T> Put<T>(Uri requestUri, Object payload, String? authorization = null, CancellationToken ct = default) where T : notnull {
String jsonString = await PutString(requestUri, payload, authorization, ct).ConfigureAwait(false);
return !String.IsNullOrEmpty(jsonString) ? Json.Deserialize<T>(jsonString) : default;
}
/// <summary>
/// Puts the specified URL.
/// </summary>
/// <param name="requestUri">The request URI.</param>
/// <param name="payload">The payload.</param>
/// <param name="authorization">The authorization.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// A task with a result of the requested collection of key/value pairs.
/// </returns>
public static async Task<IDictionary<String, Object>?> Put(Uri requestUri, Object payload, String? authorization = null, CancellationToken cancellationToken = default) {
Object response = await Put<Object>(requestUri, payload, authorization, cancellationToken).ConfigureAwait(false);
return response as IDictionary<String, Object>;
}
/// <summary>
/// Puts as string.
/// </summary>
/// <param name="requestUri">The request URI.</param>
/// <param name="payload">The payload.</param>
/// <param name="authorization">The authorization.</param>
/// <param name="ct">The cancellation token.</param>
/// <returns>
/// A task with a result of the requested string.
/// </returns>
/// <exception cref="ArgumentNullException">url.</exception>
/// <exception cref="JsonRequestException">Error PUT JSON.</exception>
public static Task<String> PutString(Uri requestUri, Object payload, String? authorization = null, CancellationToken ct = default) => SendAsync(HttpMethod.Put, requestUri, payload, authorization, ct);
/// <summary>
/// Gets as string.
/// </summary>
/// <param name="requestUri">The request URI.</param>
/// <param name="authorization">The authorization.</param>
/// <param name="ct">The cancellation token.</param>
/// <returns>
/// A task with a result of the requested string.
/// </returns>
/// <exception cref="ArgumentNullException">url.</exception>
/// <exception cref="JsonRequestException">Error GET JSON.</exception>
public static Task<String> GetString(Uri requestUri, String? authorization = null, CancellationToken ct = default) => GetString(requestUri, null, authorization, ct);
/// <summary>
/// Gets the string.
/// </summary>
/// <param name="uri">The URI.</param>
/// <param name="headers">The headers.</param>
/// <param name="authorization">The authorization.</param>
/// <param name="ct">The ct.</param>
/// <returns>
/// A task with a result of the requested string.
/// </returns>
public static async Task<String> GetString(Uri uri, IDictionary<String, IEnumerable<String>>? headers, String? authorization = null, CancellationToken ct = default) {
HttpContent response = await GetHttpContent(uri, ct, authorization, headers).ConfigureAwait(false);
return await response.ReadAsStringAsync().ConfigureAwait(false);
}
/// <summary>
/// Gets the specified URL and return the JSON data as object
/// with optional authorization token.
/// </summary>
/// <typeparam name="T">The response type.</typeparam>
/// <param name="requestUri">The request URI.</param>
/// <param name="authorization">The authorization.</param>
/// <param name="ct">The cancellation token.</param>
/// <returns>
/// A task with a result of the requested type.
/// </returns>
public static async Task<T> Get<T>(Uri requestUri, String? authorization = null, CancellationToken ct = default) where T : notnull {
String jsonString = await GetString(requestUri, authorization, ct).ConfigureAwait(false);
return !String.IsNullOrEmpty(jsonString) ? Json.Deserialize<T>(jsonString) : default;
}
/// <summary>
/// Gets the specified URL and return the JSON data as object
/// with optional authorization token.
/// </summary>
/// <typeparam name="T">The response type.</typeparam>
/// <param name="requestUri">The request URI.</param>
/// <param name="headers">The headers.</param>
/// <param name="authorization">The authorization.</param>
/// <param name="ct">The cancellation token.</param>
/// <returns>
/// A task with a result of the requested type.
/// </returns>
public static async Task<T> Get<T>(Uri requestUri, IDictionary<String, IEnumerable<String>>? headers, String? authorization = null, CancellationToken ct = default) where T : notnull {
String jsonString = await GetString(requestUri, headers, authorization, ct).ConfigureAwait(false);
return !String.IsNullOrEmpty(jsonString) ? Json.Deserialize<T>(jsonString) : default;
}
/// <summary>
/// Gets the binary.
/// </summary>
/// <param name="requestUri">The request URI.</param>
/// <param name="authorization">The authorization.</param>
/// <param name="ct">The cancellation token.</param>
/// <returns>
/// A task with a result of the requested byte array.
/// </returns>
/// <exception cref="ArgumentNullException">url.</exception>
/// <exception cref="JsonRequestException">Error GET Binary.</exception>
public static async Task<Byte[]> GetBinary(Uri requestUri, String? authorization = null, CancellationToken ct = default) {
HttpContent response = await GetHttpContent(requestUri, ct, authorization).ConfigureAwait(false);
return await response.ReadAsByteArrayAsync().ConfigureAwait(false);
}
/// <summary>
/// Authenticate against a web server using Bearer Token.
/// </summary>
/// <param name="requestUri">The request URI.</param>
/// <param name="username">The username.</param>
/// <param name="password">The password.</param>
/// <param name="ct">The cancellation token.</param>
/// <returns>
/// A task with a Dictionary with authentication data.
/// </returns>
/// <exception cref="ArgumentNullException">url
/// or
/// username.</exception>
/// <exception cref="SecurityException">Error Authenticating.</exception>
public static async Task<IDictionary<String, Object>?> Authenticate(Uri requestUri, String username, String password, CancellationToken ct = default) {
if(String.IsNullOrWhiteSpace(username)) {
throw new ArgumentNullException(nameof(username));
}
// ignore empty password for now
String content = $"grant_type=password&username={username}&password={password}";
using StringContent requestContent = new StringContent(content, Encoding.UTF8, FormType);
HttpResponseMessage response = await HttpClient.PostAsync(requestUri, requestContent, ct).ConfigureAwait(false);
if(!response.IsSuccessStatusCode) {
throw new SecurityException($"Error Authenticating. Status code: {response.StatusCode}.");
}
String jsonPayload = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
return Json.Deserialize(jsonPayload) as IDictionary<String, Object>;
}
/// <summary>
/// Posts the file.
/// </summary>
/// <param name="requestUri">The request URI.</param>
/// <param name="buffer">The buffer.</param>
/// <param name="fileName">Name of the file.</param>
/// <param name="authorization">The authorization.</param>
/// <param name="ct">The cancellation token.</param>
/// <returns>
/// A task with a result of the requested string.
/// </returns>
public static Task<String> PostFileString(Uri requestUri, Byte[] buffer, String fileName, String? authorization = null, CancellationToken ct = default) => PostString(requestUri, new { Filename = fileName, Data = buffer }, authorization, ct);
/// <summary>
/// Posts the file.
/// </summary>
/// <typeparam name="T">The response type.</typeparam>
/// <param name="requestUri">The request URI.</param>
/// <param name="buffer">The buffer.</param>
/// <param name="fileName">Name of the file.</param>
/// <param name="authorization">The authorization.</param>
/// <param name="ct">The cancellation token.</param>
/// <returns>
/// A task with a result of the requested string.
/// </returns>
public static Task<T> PostFile<T>(Uri requestUri, Byte[] buffer, String fileName, String? authorization = null, CancellationToken ct = default) where T : notnull => Post<T>(requestUri, new { Filename = fileName, Data = buffer }, authorization, ct);
/// <summary>
/// Sends the asynchronous request.
/// </summary>
/// <param name="method">The method.</param>
/// <param name="requestUri">The request URI.</param>
/// <param name="payload">The payload.</param>
/// <param name="authorization">The authorization.</param>
/// <param name="ct">The cancellation token.</param>
/// <returns>
/// A task with a result of the requested string.
/// </returns>
/// <exception cref="ArgumentNullException">requestUri.</exception>
/// <exception cref="JsonRequestException">Error {method} JSON.</exception>
public static async Task<String> SendAsync(HttpMethod method, Uri requestUri, Object payload, String? authorization = null, CancellationToken ct = default) {
using HttpResponseMessage response = await GetResponse(requestUri, authorization, null, payload, method, ct).ConfigureAwait(false);
if(!response.IsSuccessStatusCode) {
throw new JsonRequestException(
$"Error {method} JSON",
(Int32)response.StatusCode,
await response.Content.ReadAsStringAsync().ConfigureAwait(false));
}
return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
}
private static async Task<HttpContent> GetHttpContent(Uri uri, CancellationToken ct, String? authorization = null, IDictionary<String, IEnumerable<String>>? headers = null) {
HttpResponseMessage response = await GetResponse(uri, authorization, headers, ct: ct).ConfigureAwait(false);
return response.IsSuccessStatusCode ? response.Content : throw new JsonRequestException("Error GET", (Int32)response.StatusCode);
}
private static async Task<HttpResponseMessage> GetResponse(Uri uri, String? authorization, IDictionary<String, IEnumerable<String>>? headers, Object? payload = null, HttpMethod? method = default, CancellationToken ct = default) {
if(uri == null) {
throw new ArgumentNullException(nameof(uri));
}
using HttpRequestMessage requestMessage = new HttpRequestMessage(method ?? HttpMethod.Get, uri);
if(!String.IsNullOrWhiteSpace(authorization)) {
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authorization);
}
if(headers != null) {
foreach(KeyValuePair<String, IEnumerable<String>> header in headers) {
requestMessage.Headers.Add(header.Key, header.Value);
}
}
if(payload != null && requestMessage.Method != HttpMethod.Get) {
requestMessage.Content = new StringContent(Json.Serialize(payload), Encoding.UTF8, JsonMimeType);
}
return await HttpClient.SendAsync(requestMessage, ct).ConfigureAwait(false);
}
}
2019-12-04 18:57:18 +01:00
}