diff --git a/ReC.sln b/ReC.sln index 2f6d98d..7ca5a04 100644 --- a/ReC.sln +++ b/ReC.sln @@ -15,6 +15,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReC.Application", "src\ReC. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReC.Client", "src\ReC.Client\ReC.Client.csproj", "{DA3A6BDD-8045-478F-860B-D1F0EB97F02B}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}" + ProjectSection(SolutionItems) = preProject + assets\icon.png = assets\icon.png + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/assets/icon.png b/assets/icon.png new file mode 100644 index 0000000..d1ea69e Binary files /dev/null and b/assets/icon.png differ diff --git a/src/ReC.Client/DependencyInjection.cs b/src/ReC.Client/DependencyInjection.cs new file mode 100644 index 0000000..d747007 --- /dev/null +++ b/src/ReC.Client/DependencyInjection.cs @@ -0,0 +1,41 @@ +using Microsoft.Extensions.DependencyInjection; +#if NETFRAMEWORK +using System; +using System.Net.Http; +#endif + +namespace ReC.Client +{ + /// + /// Provides extension methods for setting up the ReC client in an . + /// + public static class DependencyInjection + { + /// + /// Adds and configures the for the to the specified + /// + /// The to add the services to. + /// The base URI of the ReC API. + /// An that can be used to configure the client. + public static IHttpClientBuilder AddRecClient(this IServiceCollection services, string apiUri) + { + services.AddScoped(); + return services.AddHttpClient(ReCClient.ClientName, client => + { + client.BaseAddress = new Uri(apiUri); + }); + } + + /// + /// Adds and configures the for the to the specified + /// + /// The to add the services to. + /// An action to configure the . + /// An that can be used to configure the client. + public static IHttpClientBuilder AddRecClient(this IServiceCollection services, Action configureClient) + { + services.AddScoped(); + return services.AddHttpClient(ReCClient.ClientName, configureClient); + } + } +} \ No newline at end of file diff --git a/src/ReC.Client/ReC.Client.csproj b/src/ReC.Client/ReC.Client.csproj index 983eb2b..806b76b 100644 --- a/src/ReC.Client/ReC.Client.csproj +++ b/src/ReC.Client/ReC.Client.csproj @@ -2,10 +2,36 @@ net462;net8.0 + bin\$(Configuration)\$(TargetFramework)\$(MSBuildProjectName).xml + ReC.Client + Digital Data GmbH + Digital Data GmbH + ReC.Client + Copyright 2025 + icon.png + http://git.dd:3000/AppStd/Rec.git + digital data rec api + 1.0.0-beta + 1.0.0.0 + 1.0.0.0 + Client-Bibliothek für die Interaktion mit der ReC.API, die typisierten HTTP-Zugriff und DI-Integration bietet. enable enable + + + + True + \ + + + + + + + + diff --git a/src/ReC.Client/ReCClient.cs b/src/ReC.Client/ReCClient.cs new file mode 100644 index 0000000..4249c15 --- /dev/null +++ b/src/ReC.Client/ReCClient.cs @@ -0,0 +1,124 @@ +using Microsoft.Extensions.DependencyInjection; + +#if NETFRAMEWORK +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +#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); + } + + /// + /// 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; + } + + /// + /// Synchronously invokes a ReC action for a specific profile. + /// + /// + /// This method sends a POST request to the api/RecAction/invoke/{profileId} endpoint. + /// This is the synchronous version of . + /// + /// The ID of the profile to invoke the action for. + /// if the request was successful; otherwise, . + [Obsolete("Use InvokeRecActionAsync instead to avoid potential deadlocks and improve performance.")] + public bool InvokeRecAction(int profileId) + { + var resp = _http.PostAsync($"api/RecAction/invoke/{profileId}", content: null).GetAwaiter().GetResult(); + return resp.IsSuccessStatusCode; + } + + #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 + } +} \ No newline at end of file