using Microsoft.Extensions.DependencyInjection;
using System;
using System.Globalization;
using System.Linq;
using System.Net.Http.Json;
using System.Threading;
using System.Threading.Tasks;
#if NETFRAMEWORK
using System.Net.Http;
#endif
namespace ReC.Client
{
///
/// A client for interacting with the ReC API.
///
public class ReCClient
{
private readonly HttpClient _http;
///
/// A unique name for the HttpClient used by the ReCClient.
///
public static readonly string ClientName = Guid.NewGuid().ToString();
///
/// Initializes a new instance of the class.
///
/// The factory to create HttpClients.
public ReCClient(IHttpClientFactory httpClientFactory)
{
_http = httpClientFactory.CreateClient(ClientName);
}
#if NETFRAMEWORK
private static string BuildQuery(params (string Key, object Value)[] parameters)
#else
private static string BuildQuery(params (string Key, object? Value)[] parameters)
#endif
{
var parts = parameters
.Where(p => p.Value != null)
.Select(p => $"{Uri.EscapeDataString(p.Key)}={Uri.EscapeDataString(Convert.ToString(p.Value, CultureInfo.InvariantCulture) ?? string.Empty)}");
var query = string.Join("&", parts);
return string.IsNullOrWhiteSpace(query) ? string.Empty : $"?{query}";
}
private static JsonContent ToJsonContent(T payload) => JsonContent.Create(payload);
#region RecActionController
///
/// Asynchronously invokes a ReC action for a specific profile.
///
///
/// This method sends a POST request to the api/RecAction/invoke/{profileId} endpoint.
///
/// The ID of the profile to invoke the action for.
/// A token to cancel the asynchronous operation.
/// A that represents the asynchronous operation. The task result is if the request was successful; otherwise, .
public async Task InvokeRecActionAsync(int profileId, CancellationToken cancellationToken = default)
{
var resp = await _http.PostAsync($"api/RecAction/invoke/{profileId}", content: null, cancellationToken);
return resp.IsSuccessStatusCode;
}
///
/// Asynchronously retrieves a list of ReC actions for the configured profile.
///
///
/// This method sends a GET request to the api/RecAction endpoint with optional query parameters.
///
/// The ID of the profile to retrieve actions for. If null, actions for all profiles are retrieved.
/// Filter for invoked actions. If null, both invoked and not invoked actions are retrieved.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task GetRecActionsAsync(long? profileId = null, bool? invoked = null, CancellationToken cancel = default)
{
var query = BuildQuery(("ProfileId", profileId), ("Invoked", invoked));
return _http.GetAsync($"api/RecAction{query}", cancel);
}
///
/// Asynchronously creates a new ReC action.
///
///
/// This method sends a POST request to the api/RecAction endpoint with the action data as JSON.
///
/// The action data to create.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task CreateRecActionAsync(T procedure, CancellationToken cancel = default)
=> _http.PostAsync("api/RecAction", ToJsonContent(procedure), cancel);
///
/// Asynchronously updates an existing ReC action.
///
///
/// This method sends a PUT request to the api/RecAction/{id} endpoint with the updated action data as JSON.
///
/// The ID of the action to update.
/// The updated action data.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task UpdateRecActionAsync(long id, T procedure, CancellationToken cancel = default)
=> _http.PutAsync($"api/RecAction/{id}", ToJsonContent(procedure), cancel);
///
/// Asynchronously deletes one or more ReC actions.
///
///
/// This method sends a DELETE request to the api/RecAction endpoint with the IDs of the actions to delete as JSON.
///
/// An object containing the IDs of the actions to delete.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task DeleteRecActionsAsync(T procedure, CancellationToken cancel = default)
{
var request = new HttpRequestMessage(HttpMethod.Delete, "api/RecAction")
{
Content = ToJsonContent(procedure)
};
return _http.SendAsync(request, cancel);
}
#endregion
#region OutResController
///
/// Asynchronously retrieves results for the configured profile.
///
///
/// This method sends a GET request to the api/OutRes endpoint with optional query parameters.
///
/// Filter by result ID.
/// Filter by action ID.
/// Filter by profile ID.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task GetResultsAsync(long? id = null, long? actionId = null, long? profileId = null, CancellationToken cancel = default)
{
var query = BuildQuery(("Id", id), ("ActionId", actionId), ("ProfileId", profileId));
return _http.GetAsync($"api/OutRes{query}", cancel);
}
///
/// Asynchronously creates a new result.
///
///
/// This method sends a POST request to the api/OutRes endpoint with the result data as JSON.
///
/// The result data to create.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task CreateResultAsync(T procedure, CancellationToken cancel = default)
=> _http.PostAsync("api/OutRes", ToJsonContent(procedure), cancel);
///
/// Asynchronously updates an existing result.
///
///
/// This method sends a PUT request to the api/OutRes/{id} endpoint with the updated result data as JSON.
///
/// The ID of the result to update.
/// The updated result data.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task UpdateResultAsync(long id, T procedure, CancellationToken cancel = default)
=> _http.PutAsync($"api/OutRes/{id}", ToJsonContent(procedure), cancel);
///
/// Asynchronously deletes one or more results.
///
///
/// This method sends a DELETE request to the api/OutRes endpoint with the IDs of the results to delete as JSON.
///
/// An object containing the IDs of the results to delete.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task DeleteResultsAsync(T procedure, CancellationToken cancel = default)
{
var request = new HttpRequestMessage(HttpMethod.Delete, "api/OutRes")
{
Content = ToJsonContent(procedure)
};
return _http.SendAsync(request, cancel);
}
#endregion
#region ProfileController
///
/// Asynchronously retrieves a profile by ID.
///
///
/// This method sends a GET request to the api/Profile endpoint with the profile ID as a query parameter.
///
/// The ID of the profile to retrieve.
/// Whether to include associated actions in the response.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task GetProfileAsync(long id, bool includeActions = false, CancellationToken cancel = default)
{
var query = BuildQuery(("Id", id), ("IncludeActions", includeActions));
return _http.GetAsync($"api/Profile{query}", cancel);
}
///
/// Asynchronously creates a new profile.
///
///
/// This method sends a POST request to the api/Profile endpoint with the profile data as JSON.
///
/// The profile data to create.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task CreateProfileAsync(T procedure, CancellationToken cancel = default)
=> _http.PostAsync("api/Profile", ToJsonContent(procedure), cancel);
///
/// Asynchronously updates an existing profile.
///
///
/// This method sends a PUT request to the api/Profile/{id} endpoint with the updated profile data as JSON.
///
/// The ID of the profile to update.
/// The updated profile data.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task UpdateProfileAsync(long id, T procedure, CancellationToken cancel = default)
=> _http.PutAsync($"api/Profile/{id}", ToJsonContent(procedure), cancel);
///
/// Asynchronously deletes one or more profiles.
///
///
/// This method sends a DELETE request to the api/Profile endpoint with the IDs of the profiles to delete as JSON.
///
/// An object containing the IDs of the profiles to delete.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task DeleteProfilesAsync(T procedure, CancellationToken cancel = default)
{
var request = new HttpRequestMessage(HttpMethod.Delete, "api/Profile")
{
Content = ToJsonContent(procedure)
};
return _http.SendAsync(request, cancel);
}
#endregion
#region EndpointAuthController
///
/// Asynchronously creates a new endpoint authentication.
///
///
/// This method sends a POST request to the api/EndpointAuth endpoint with the authentication data as JSON.
///
/// The authentication data to create.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task CreateEndpointAuthAsync(T procedure, CancellationToken cancel = default)
=> _http.PostAsync("api/EndpointAuth", ToJsonContent(procedure), cancel);
///
/// Asynchronously updates an existing endpoint authentication.
///
///
/// This method sends a PUT request to the api/EndpointAuth/{id} endpoint with the updated authentication data as JSON.
///
/// The ID of the authentication to update.
/// The updated authentication data.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task UpdateEndpointAuthAsync(long id, T procedure, CancellationToken cancel = default)
=> _http.PutAsync($"api/EndpointAuth/{id}", ToJsonContent(procedure), cancel);
///
/// Asynchronously deletes one or more endpoint authentications.
///
///
/// This method sends a DELETE request to the api/EndpointAuth endpoint with the IDs of the authentications to delete as JSON.
///
/// An object containing the IDs of the authentications to delete.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task DeleteEndpointAuthAsync(T procedure, CancellationToken cancel = default)
{
var request = new HttpRequestMessage(HttpMethod.Delete, "api/EndpointAuth")
{
Content = ToJsonContent(procedure)
};
return _http.SendAsync(request, cancel);
}
#endregion
#region EndpointParamsController
///
/// Asynchronously creates new endpoint parameters.
///
///
/// This method sends a POST request to the api/EndpointParams endpoint with the parameters data as JSON.
///
/// The parameters data to create.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task CreateEndpointParamsAsync(T procedure, CancellationToken cancel = default)
=> _http.PostAsync("api/EndpointParams", ToJsonContent(procedure), cancel);
///
/// Asynchronously updates existing endpoint parameters.
///
///
/// This method sends a PUT request to the api/EndpointParams/{id} endpoint with the updated parameters data as JSON.
///
/// The ID of the parameters to update.
/// The updated parameters data.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task UpdateEndpointParamsAsync(long id, T procedure, CancellationToken cancel = default)
=> _http.PutAsync($"api/EndpointParams/{id}", ToJsonContent(procedure), cancel);
///
/// Asynchronously deletes one or more endpoint parameters.
///
///
/// This method sends a DELETE request to the api/EndpointParams endpoint with the IDs of the parameters to delete as JSON.
///
/// An object containing the IDs of the parameters to delete.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task DeleteEndpointParamsAsync(T procedure, CancellationToken cancel = default)
{
var request = new HttpRequestMessage(HttpMethod.Delete, "api/EndpointParams")
{
Content = ToJsonContent(procedure)
};
return _http.SendAsync(request, cancel);
}
#endregion
#region EndpointsController
///
/// Asynchronously creates a new endpoint.
///
///
/// This method sends a POST request to the api/Endpoints endpoint with the endpoint data as JSON.
///
/// The endpoint data to create.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task CreateEndpointAsync(T procedure, CancellationToken cancel = default)
=> _http.PostAsync("api/Endpoints", ToJsonContent(procedure), cancel);
///
/// Asynchronously updates an existing endpoint.
///
///
/// This method sends a PUT request to the api/Endpoints/{id} endpoint with the updated endpoint data as JSON.
///
/// The ID of the endpoint to update.
/// The updated endpoint data.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task UpdateEndpointAsync(long id, T procedure, CancellationToken cancel = default)
=> _http.PutAsync($"api/Endpoints/{id}", ToJsonContent(procedure), cancel);
///
/// Asynchronously deletes one or more endpoints.
///
///
/// This method sends a DELETE request to the api/Endpoints endpoint with the IDs of the endpoints to delete as JSON.
///
/// An object containing the IDs of the endpoints to delete.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task DeleteEndpointAsync(T procedure, CancellationToken cancel = default)
{
var request = new HttpRequestMessage(HttpMethod.Delete, "api/Endpoints")
{
Content = ToJsonContent(procedure)
};
return _http.SendAsync(request, cancel);
}
#endregion
#region CommonController
///
/// Asynchronously creates a new object.
///
///
/// This method sends a POST request to the api/Common endpoint with the object data as JSON.
///
/// The object data to create.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task CreateObjectAsync(T procedure, CancellationToken cancel = default)
=> _http.PostAsync("api/Common", ToJsonContent(procedure), cancel);
///
/// Asynchronously updates an existing object.
///
///
/// This method sends a PUT request to the api/Common endpoint with the updated object data as JSON.
///
/// The updated object data.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task UpdateObjectAsync(T procedure, CancellationToken cancel = default)
=> _http.PutAsync("api/Common", ToJsonContent(procedure), cancel);
///
/// Asynchronously deletes one or more objects.
///
///
/// This method sends a DELETE request to the api/Common endpoint with the IDs of the objects to delete as JSON.
///
/// An object containing the IDs of the objects to delete.
/// A token to cancel the asynchronous operation.
/// A task representing the asynchronous operation, with a result containing the response data.
public Task DeleteObjectAsync(T procedure, CancellationToken cancel = default)
{
var request = new HttpRequestMessage(HttpMethod.Delete, "api/Common")
{
Content = ToJsonContent(procedure)
};
return _http.SendAsync(request, cancel);
}
#endregion
#region Static
private static readonly IServiceCollection Services = new ServiceCollection();
#if NET8_0_OR_GREATER
private static IServiceProvider? Provider = null;
#else
private static IServiceProvider Provider = null;
#endif
///
/// Configures and builds the static for creating instances.
///
///
/// This method should only be called once during application startup.
///
/// The base URI of the ReC API.
/// Thrown if the static provider has already been built.
[Obsolete("Use a local service collection instead of the static provider.")]
public static void BuildStaticClient(string apiUri)
{
if(Provider != null)
throw new InvalidOperationException("Static Provider is already built.");
Services.AddRecClient(apiUri);
Provider = Services.BuildServiceProvider();
}
///
/// Configures and builds the static for creating instances.
///
///
/// This method should only be called once during application startup.
///
/// An action to configure the .
/// Thrown if the static provider has already been built.
[Obsolete("Use a local service collection instead of the static provider.")]
public static void BuildStaticClient(Action configureClient)
{
if (Provider != null)
throw new InvalidOperationException("Static Provider is already built.");
Services.AddRecClient(configureClient);
Provider = Services.BuildServiceProvider();
}
///
/// Creates a new instance using the statically configured provider.
///
/// A new instance of the .
/// Thrown if has not been called yet.
[Obsolete("Use a local service collection instead of the static provider.")]
public static ReCClient Create()
{
if (Provider == null)
throw new InvalidOperationException("Static Provider is not built. Call BuildStaticClient first.");
return Provider.GetRequiredService();
}
#endregion
}
///
/// Specifies which part of the result to return for result view endpoints.
///
public enum ResultType
{
Full,
OnlyHeader,
OnlyBody
}
}