Refactor ReCClient to use modular API group classes

Refactored ReCClient to expose grouped endpoint APIs as properties (e.g., RecActions, Results, Profiles, etc.), each handled by its own class. Removed direct endpoint methods from ReCClient and delegated them to these new API classes. Cleaned up using directives and improved code modularity for better maintainability and discoverability.
This commit is contained in:
2026-01-16 11:34:06 +01:00
parent b639df0a39
commit a17d260c6c

View File

@@ -1,14 +1,7 @@
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
using System.Threading.Tasks;
namespace ReC.Client
{
@@ -24,6 +17,41 @@ namespace ReC.Client
/// </summary>
public static readonly string ClientName = Guid.NewGuid().ToString();
/// <summary>
/// Provides access to RecAction endpoints.
/// </summary>
public RecActionApi RecActions { get; }
/// <summary>
/// Provides access to OutRes endpoints.
/// </summary>
public ResultApi Results { get; }
/// <summary>
/// Provides access to Profile endpoints.
/// </summary>
public ProfileApi Profiles { get; }
/// <summary>
/// Provides access to EndpointAuth endpoints.
/// </summary>
public EndpointAuthApi EndpointAuth { get; }
/// <summary>
/// Provides access to EndpointParams endpoints.
/// </summary>
public EndpointParamsApi EndpointParams { get; }
/// <summary>
/// Provides access to Endpoints endpoints.
/// </summary>
public EndpointsApi Endpoints { get; }
/// <summary>
/// Provides access to Common endpoints.
/// </summary>
public CommonApi Common { get; }
/// <summary>
/// Initializes a new instance of the <see cref="ReCClient"/> class.
/// </summary>
@@ -31,402 +59,15 @@ namespace ReC.Client
public ReCClient(IHttpClientFactory httpClientFactory)
{
_http = httpClientFactory.CreateClient(ClientName);
RecActions = new RecActionApi(_http);
Results = new ResultApi(_http);
Profiles = new ProfileApi(_http);
EndpointAuth = new EndpointAuthApi(_http);
EndpointParams = new EndpointParamsApi(_http);
Endpoints = new EndpointsApi(_http);
Common = new CommonApi(_http);
}
#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>(T payload) => JsonContent.Create(payload);
#region RecActionController
/// <summary>
/// Asynchronously invokes a ReC action for a specific profile.
/// </summary>
/// <remarks>
/// This method sends a POST request to the <c>api/RecAction/invoke/{profileId}</c> endpoint.
/// </remarks>
/// <param name="profileId">The ID of the profile to invoke the action for.</param>
/// <param name="cancellationToken">A token to cancel the asynchronous operation.</param>
/// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous operation. The task result is <see langword="true"/> if the request was successful; otherwise, <see langword="false"/>.</returns>
public async Task<bool> InvokeRecActionAsync(int profileId, CancellationToken cancellationToken = default)
{
var resp = await _http.PostAsync($"api/RecAction/invoke/{profileId}", content: null, cancellationToken);
return resp.IsSuccessStatusCode;
}
/// <summary>
/// Asynchronously retrieves a list of ReC actions for the configured profile.
/// </summary>
/// <remarks>
/// This method sends a GET request to the <c>api/RecAction</c> endpoint with optional query parameters.
/// </remarks>
/// <param name="profileId">The ID of the profile to retrieve actions for. If <c>null</c>, actions for all profiles are retrieved.</param>
/// <param name="invoked">Filter for invoked actions. If <c>null</c>, both invoked and not invoked actions are retrieved.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> GetRecActionsAsync(long? profileId = null, bool? invoked = null, CancellationToken cancel = default)
{
var query = BuildQuery(("ProfileId", profileId), ("Invoked", invoked));
return _http.GetAsync($"api/RecAction{query}", cancel);
}
/// <summary>
/// Asynchronously creates a new ReC action.
/// </summary>
/// <remarks>
/// This method sends a POST request to the <c>api/RecAction</c> endpoint with the action data as JSON.
/// </remarks>
/// <param name="procedure">The action data to create.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> CreateRecActionAsync<T>(T procedure, CancellationToken cancel = default)
=> _http.PostAsync("api/RecAction", ToJsonContent(procedure), cancel);
/// <summary>
/// Asynchronously updates an existing ReC action.
/// </summary>
/// <remarks>
/// This method sends a PUT request to the <c>api/RecAction/{id}</c> endpoint with the updated action data as JSON.
/// </remarks>
/// <param name="id">The ID of the action to update.</param>
/// <param name="procedure">The updated action data.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> UpdateRecActionAsync<T>(long id, T procedure, CancellationToken cancel = default)
=> _http.PutAsync($"api/RecAction/{id}", ToJsonContent(procedure), cancel);
/// <summary>
/// Asynchronously deletes one or more ReC actions.
/// </summary>
/// <remarks>
/// This method sends a DELETE request to the <c>api/RecAction</c> endpoint with the IDs of the actions to delete as JSON.
/// </remarks>
/// <param name="procedure">An object containing the IDs of the actions to delete.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> DeleteRecActionsAsync<T>(T procedure, CancellationToken cancel = default)
{
var request = new HttpRequestMessage(HttpMethod.Delete, "api/RecAction")
{
Content = ToJsonContent(procedure)
};
return _http.SendAsync(request, cancel);
}
#endregion
#region OutResController
/// <summary>
/// Asynchronously retrieves results for the configured profile.
/// </summary>
/// <remarks>
/// This method sends a GET request to the <c>api/OutRes</c> endpoint with optional query parameters.
/// </remarks>
/// <param name="id">Filter by result ID.</param>
/// <param name="actionId">Filter by action ID.</param>
/// <param name="profileId">Filter by profile ID.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> 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);
}
/// <summary>
/// Asynchronously creates a new result.
/// </summary>
/// <remarks>
/// This method sends a POST request to the <c>api/OutRes</c> endpoint with the result data as JSON.
/// </remarks>
/// <param name="procedure">The result data to create.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> CreateResultAsync<T>(T procedure, CancellationToken cancel = default)
=> _http.PostAsync("api/OutRes", ToJsonContent(procedure), cancel);
/// <summary>
/// Asynchronously updates an existing result.
/// </summary>
/// <remarks>
/// This method sends a PUT request to the <c>api/OutRes/{id}</c> endpoint with the updated result data as JSON.
/// </remarks>
/// <param name="id">The ID of the result to update.</param>
/// <param name="procedure">The updated result data.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> UpdateResultAsync<T>(long id, T procedure, CancellationToken cancel = default)
=> _http.PutAsync($"api/OutRes/{id}", ToJsonContent(procedure), cancel);
/// <summary>
/// Asynchronously deletes one or more results.
/// </summary>
/// <remarks>
/// This method sends a DELETE request to the <c>api/OutRes</c> endpoint with the IDs of the results to delete as JSON.
/// </remarks>
/// <param name="procedure">An object containing the IDs of the results to delete.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> DeleteResultsAsync<T>(T procedure, CancellationToken cancel = default)
{
var request = new HttpRequestMessage(HttpMethod.Delete, "api/OutRes")
{
Content = ToJsonContent(procedure)
};
return _http.SendAsync(request, cancel);
}
#endregion
#region ProfileController
/// <summary>
/// Asynchronously retrieves a profile by ID.
/// </summary>
/// <remarks>
/// This method sends a GET request to the <c>api/Profile</c> endpoint with the profile ID as a query parameter.
/// </remarks>
/// <param name="id">The ID of the profile to retrieve.</param>
/// <param name="includeActions">Whether to include associated actions in the response.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> GetProfileAsync(long id, bool includeActions = false, CancellationToken cancel = default)
{
var query = BuildQuery(("Id", id), ("IncludeActions", includeActions));
return _http.GetAsync($"api/Profile{query}", cancel);
}
/// <summary>
/// Asynchronously creates a new profile.
/// </summary>
/// <remarks>
/// This method sends a POST request to the <c>api/Profile</c> endpoint with the profile data as JSON.
/// </remarks>
/// <param name="procedure">The profile data to create.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> CreateProfileAsync<T>(T procedure, CancellationToken cancel = default)
=> _http.PostAsync("api/Profile", ToJsonContent(procedure), cancel);
/// <summary>
/// Asynchronously updates an existing profile.
/// </summary>
/// <remarks>
/// This method sends a PUT request to the <c>api/Profile/{id}</c> endpoint with the updated profile data as JSON.
/// </remarks>
/// <param name="id">The ID of the profile to update.</param>
/// <param name="procedure">The updated profile data.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> UpdateProfileAsync<T>(long id, T procedure, CancellationToken cancel = default)
=> _http.PutAsync($"api/Profile/{id}", ToJsonContent(procedure), cancel);
/// <summary>
/// Asynchronously deletes one or more profiles.
/// </summary>
/// <remarks>
/// This method sends a DELETE request to the <c>api/Profile</c> endpoint with the IDs of the profiles to delete as JSON.
/// </remarks>
/// <param name="procedure">An object containing the IDs of the profiles to delete.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> DeleteProfilesAsync<T>(T procedure, CancellationToken cancel = default)
{
var request = new HttpRequestMessage(HttpMethod.Delete, "api/Profile")
{
Content = ToJsonContent(procedure)
};
return _http.SendAsync(request, cancel);
}
#endregion
#region EndpointAuthController
/// <summary>
/// Asynchronously creates a new endpoint authentication.
/// </summary>
/// <remarks>
/// This method sends a POST request to the <c>api/EndpointAuth</c> endpoint with the authentication data as JSON.
/// </remarks>
/// <param name="procedure">The authentication data to create.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> CreateEndpointAuthAsync<T>(T procedure, CancellationToken cancel = default)
=> _http.PostAsync("api/EndpointAuth", ToJsonContent(procedure), cancel);
/// <summary>
/// Asynchronously updates an existing endpoint authentication.
/// </summary>
/// <remarks>
/// This method sends a PUT request to the <c>api/EndpointAuth/{id}</c> endpoint with the updated authentication data as JSON.
/// </remarks>
/// <param name="id">The ID of the authentication to update.</param>
/// <param name="procedure">The updated authentication data.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> UpdateEndpointAuthAsync<T>(long id, T procedure, CancellationToken cancel = default)
=> _http.PutAsync($"api/EndpointAuth/{id}", ToJsonContent(procedure), cancel);
/// <summary>
/// Asynchronously deletes one or more endpoint authentications.
/// </summary>
/// <remarks>
/// This method sends a DELETE request to the <c>api/EndpointAuth</c> endpoint with the IDs of the authentications to delete as JSON.
/// </remarks>
/// <param name="procedure">An object containing the IDs of the authentications to delete.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> DeleteEndpointAuthAsync<T>(T procedure, CancellationToken cancel = default)
{
var request = new HttpRequestMessage(HttpMethod.Delete, "api/EndpointAuth")
{
Content = ToJsonContent(procedure)
};
return _http.SendAsync(request, cancel);
}
#endregion
#region EndpointParamsController
/// <summary>
/// Asynchronously creates new endpoint parameters.
/// </summary>
/// <remarks>
/// This method sends a POST request to the <c>api/EndpointParams</c> endpoint with the parameters data as JSON.
/// </remarks>
/// <param name="procedure">The parameters data to create.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> CreateEndpointParamsAsync<T>(T procedure, CancellationToken cancel = default)
=> _http.PostAsync("api/EndpointParams", ToJsonContent(procedure), cancel);
/// <summary>
/// Asynchronously updates existing endpoint parameters.
/// </summary>
/// <remarks>
/// This method sends a PUT request to the <c>api/EndpointParams/{id}</c> endpoint with the updated parameters data as JSON.
/// </remarks>
/// <param name="id">The ID of the parameters to update.</param>
/// <param name="procedure">The updated parameters data.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> UpdateEndpointParamsAsync<T>(long id, T procedure, CancellationToken cancel = default)
=> _http.PutAsync($"api/EndpointParams/{id}", ToJsonContent(procedure), cancel);
/// <summary>
/// Asynchronously deletes one or more endpoint parameters.
/// </summary>
/// <remarks>
/// This method sends a DELETE request to the <c>api/EndpointParams</c> endpoint with the IDs of the parameters to delete as JSON.
/// </remarks>
/// <param name="procedure">An object containing the IDs of the parameters to delete.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> DeleteEndpointParamsAsync<T>(T procedure, CancellationToken cancel = default)
{
var request = new HttpRequestMessage(HttpMethod.Delete, "api/EndpointParams")
{
Content = ToJsonContent(procedure)
};
return _http.SendAsync(request, cancel);
}
#endregion
#region EndpointsController
/// <summary>
/// Asynchronously creates a new endpoint.
/// </summary>
/// <remarks>
/// This method sends a POST request to the <c>api/Endpoints</c> endpoint with the endpoint data as JSON.
/// </remarks>
/// <param name="procedure">The endpoint data to create.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> CreateEndpointAsync<T>(T procedure, CancellationToken cancel = default)
=> _http.PostAsync("api/Endpoints", ToJsonContent(procedure), cancel);
/// <summary>
/// Asynchronously updates an existing endpoint.
/// </summary>
/// <remarks>
/// This method sends a PUT request to the <c>api/Endpoints/{id}</c> endpoint with the updated endpoint data as JSON.
/// </remarks>
/// <param name="id">The ID of the endpoint to update.</param>
/// <param name="procedure">The updated endpoint data.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> UpdateEndpointAsync<T>(long id, T procedure, CancellationToken cancel = default)
=> _http.PutAsync($"api/Endpoints/{id}", ToJsonContent(procedure), cancel);
/// <summary>
/// Asynchronously deletes one or more endpoints.
/// </summary>
/// <remarks>
/// This method sends a DELETE request to the <c>api/Endpoints</c> endpoint with the IDs of the endpoints to delete as JSON.
/// </remarks>
/// <param name="procedure">An object containing the IDs of the endpoints to delete.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> DeleteEndpointAsync<T>(T procedure, CancellationToken cancel = default)
{
var request = new HttpRequestMessage(HttpMethod.Delete, "api/Endpoints")
{
Content = ToJsonContent(procedure)
};
return _http.SendAsync(request, cancel);
}
#endregion
#region CommonController
/// <summary>
/// Asynchronously creates a new object.
/// </summary>
/// <remarks>
/// This method sends a POST request to the <c>api/Common</c> endpoint with the object data as JSON.
/// </remarks>
/// <param name="procedure">The object data to create.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> CreateObjectAsync<T>(T procedure, CancellationToken cancel = default)
=> _http.PostAsync("api/Common", ToJsonContent(procedure), cancel);
/// <summary>
/// Asynchronously updates an existing object.
/// </summary>
/// <remarks>
/// This method sends a PUT request to the <c>api/Common</c> endpoint with the updated object data as JSON.
/// </remarks>
/// <param name="procedure">The updated object data.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> UpdateObjectAsync<T>(T procedure, CancellationToken cancel = default)
=> _http.PutAsync("api/Common", ToJsonContent(procedure), cancel);
/// <summary>
/// Asynchronously deletes one or more objects.
/// </summary>
/// <remarks>
/// This method sends a DELETE request to the <c>api/Common</c> endpoint with the IDs of the objects to delete as JSON.
/// </remarks>
/// <param name="procedure">An object containing the IDs of the objects to delete.</param>
/// <param name="cancel">A token to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="HttpResponseMessage"/> result containing the response data.</returns>
public Task<HttpResponseMessage> DeleteObjectAsync<T>(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();