Add ILogger support for enhanced API call logging

Introduced optional ILogger support across BaseCrudApi and its
derived classes to enable logging of API call outcomes. Updated
constructors to accept an optional ILogger parameter, with
conditional compilation for .NET Framework compatibility.

Replaced EnsureSuccessAsync with HandleResponseAsync in CRUD
methods to integrate logging. Updated derived API classes
(CommonApi, EndpointAuthApi, EndpointParamsApi, EndpointsApi,
ProfileApi, RecActionApi, ResultApi) to pass ILogger to the base
class.

Added Microsoft.Extensions.Logging imports and ensured backward
compatibility by making ILogger optional and handling nullable
reference types in non-.NET Framework environments.
This commit is contained in:
2026-05-19 19:09:08 +02:00
parent 7ed348832c
commit 91c166dc4d
8 changed files with 70 additions and 12 deletions

View File

@@ -2,6 +2,7 @@ using System;
using System.Net.Http; using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace ReC.Client.Api namespace ReC.Client.Api
{ {
@@ -20,15 +21,30 @@ namespace ReC.Client.Api
/// </summary> /// </summary>
protected readonly string ResourcePath; protected readonly string ResourcePath;
/// <summary>
/// An optional logger used to record API call outcomes. May be <see langword="null"/>.
/// </summary>
#if NETFRAMEWORK
protected readonly ILogger Logger;
#else
protected readonly ILogger? Logger;
#endif
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="BaseCrudApi"/> class. /// Initializes a new instance of the <see cref="BaseCrudApi"/> class.
/// </summary> /// </summary>
/// <param name="http">The HTTP client used for requests.</param> /// <param name="http">The HTTP client used for requests.</param>
/// <param name="resourcePath">The base resource path for the API endpoint.</param> /// <param name="resourcePath">The base resource path for the API endpoint.</param>
protected BaseCrudApi(HttpClient http, string resourcePath) /// <param name="logger">An optional logger used to record API call outcomes.</param>
#if NETFRAMEWORK
protected BaseCrudApi(HttpClient http, string resourcePath, ILogger logger = null)
#else
protected BaseCrudApi(HttpClient http, string resourcePath, ILogger? logger = null)
#endif
{ {
Http = http ?? throw new ArgumentNullException(nameof(http)); Http = http ?? throw new ArgumentNullException(nameof(http));
ResourcePath = resourcePath ?? throw new ArgumentNullException(nameof(resourcePath)); ResourcePath = resourcePath ?? throw new ArgumentNullException(nameof(resourcePath));
Logger = logger;
} }
/// <summary> /// <summary>
@@ -43,7 +59,7 @@ namespace ReC.Client.Api
using (var content = ReCClientHelpers.ToJsonContent(payload)) using (var content = ReCClientHelpers.ToJsonContent(payload))
using (var resp = await Http.PostAsync(ResourcePath, content, cancel)) using (var resp = await Http.PostAsync(ResourcePath, content, cancel))
{ {
await ReCClientHelpers.EnsureSuccessAsync(resp, cancel).ConfigureAwait(false); await ReCClientHelpers.HandleResponseAsync(resp, Logger, cancel).ConfigureAwait(false);
} }
} }
@@ -60,7 +76,7 @@ namespace ReC.Client.Api
using (var content = ReCClientHelpers.ToJsonContent(payload)) using (var content = ReCClientHelpers.ToJsonContent(payload))
using (var resp = await Http.PutAsync($"{ResourcePath}/{id}", content, cancel)) using (var resp = await Http.PutAsync($"{ResourcePath}/{id}", content, cancel))
{ {
await ReCClientHelpers.EnsureSuccessAsync(resp, cancel).ConfigureAwait(false); await ReCClientHelpers.HandleResponseAsync(resp, Logger, cancel).ConfigureAwait(false);
} }
} }
@@ -79,7 +95,7 @@ namespace ReC.Client.Api
}) })
using (var resp = await Http.SendAsync(request, cancel)) using (var resp = await Http.SendAsync(request, cancel))
{ {
await ReCClientHelpers.EnsureSuccessAsync(resp, cancel).ConfigureAwait(false); await ReCClientHelpers.HandleResponseAsync(resp, Logger, cancel).ConfigureAwait(false);
} }
} }
} }

View File

@@ -1,6 +1,7 @@
using System.Net.Http; using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace ReC.Client.Api namespace ReC.Client.Api
{ {
@@ -13,7 +14,12 @@ namespace ReC.Client.Api
/// Initializes a new instance of the <see cref="CommonApi"/> class. /// Initializes a new instance of the <see cref="CommonApi"/> class.
/// </summary> /// </summary>
/// <param name="http">The HTTP client used for requests.</param> /// <param name="http">The HTTP client used for requests.</param>
public CommonApi(HttpClient http) : base(http, "api/Common") /// <param name="logger">An optional logger used to record API call outcomes.</param>
#if NETFRAMEWORK
public CommonApi(HttpClient http, ILogger logger = null) : base(http, "api/Common", logger)
#else
public CommonApi(HttpClient http, ILogger? logger = null) : base(http, "api/Common", logger)
#endif
{ {
} }
} }

View File

@@ -1,6 +1,7 @@
using System.Net.Http; using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace ReC.Client.Api namespace ReC.Client.Api
{ {
@@ -13,7 +14,12 @@ namespace ReC.Client.Api
/// Initializes a new instance of the <see cref="EndpointAuthApi"/> class. /// Initializes a new instance of the <see cref="EndpointAuthApi"/> class.
/// </summary> /// </summary>
/// <param name="http">The HTTP client used for requests.</param> /// <param name="http">The HTTP client used for requests.</param>
public EndpointAuthApi(HttpClient http) : base(http, "api/EndpointAuth") /// <param name="logger">An optional logger used to record API call outcomes.</param>
#if NETFRAMEWORK
public EndpointAuthApi(HttpClient http, ILogger logger = null) : base(http, "api/EndpointAuth", logger)
#else
public EndpointAuthApi(HttpClient http, ILogger? logger = null) : base(http, "api/EndpointAuth", logger)
#endif
{ {
} }
} }

View File

@@ -1,6 +1,7 @@
using System.Net.Http; using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace ReC.Client.Api namespace ReC.Client.Api
{ {
@@ -13,7 +14,12 @@ namespace ReC.Client.Api
/// Initializes a new instance of the <see cref="EndpointParamsApi"/> class. /// Initializes a new instance of the <see cref="EndpointParamsApi"/> class.
/// </summary> /// </summary>
/// <param name="http">The HTTP client used for requests.</param> /// <param name="http">The HTTP client used for requests.</param>
public EndpointParamsApi(HttpClient http) : base(http, "api/EndpointParams") /// <param name="logger">An optional logger used to record API call outcomes.</param>
#if NETFRAMEWORK
public EndpointParamsApi(HttpClient http, ILogger logger = null) : base(http, "api/EndpointParams", logger)
#else
public EndpointParamsApi(HttpClient http, ILogger? logger = null) : base(http, "api/EndpointParams", logger)
#endif
{ {
} }
} }

View File

@@ -1,6 +1,7 @@
using System.Net.Http; using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace ReC.Client.Api namespace ReC.Client.Api
{ {
@@ -13,7 +14,12 @@ namespace ReC.Client.Api
/// Initializes a new instance of the <see cref="EndpointsApi"/> class. /// Initializes a new instance of the <see cref="EndpointsApi"/> class.
/// </summary> /// </summary>
/// <param name="http">The HTTP client used for requests.</param> /// <param name="http">The HTTP client used for requests.</param>
public EndpointsApi(HttpClient http) : base(http, "api/Endpoints") /// <param name="logger">An optional logger used to record API call outcomes.</param>
#if NETFRAMEWORK
public EndpointsApi(HttpClient http, ILogger logger = null) : base(http, "api/Endpoints", logger)
#else
public EndpointsApi(HttpClient http, ILogger? logger = null) : base(http, "api/Endpoints", logger)
#endif
{ {
} }
} }

View File

@@ -1,6 +1,7 @@
using System.Net.Http; using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace ReC.Client.Api namespace ReC.Client.Api
{ {
@@ -13,7 +14,12 @@ namespace ReC.Client.Api
/// Initializes a new instance of the <see cref="ProfileApi"/> class. /// Initializes a new instance of the <see cref="ProfileApi"/> class.
/// </summary> /// </summary>
/// <param name="http">The HTTP client used for requests.</param> /// <param name="http">The HTTP client used for requests.</param>
public ProfileApi(HttpClient http) : base(http, "api/Profile") /// <param name="logger">An optional logger used to record API call outcomes.</param>
#if NETFRAMEWORK
public ProfileApi(HttpClient http, ILogger logger = null) : base(http, "api/Profile", logger)
#else
public ProfileApi(HttpClient http, ILogger? logger = null) : base(http, "api/Profile", logger)
#endif
{ {
} }

View File

@@ -1,6 +1,7 @@
using System.Net.Http; using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace ReC.Client.Api namespace ReC.Client.Api
{ {
@@ -13,7 +14,12 @@ namespace ReC.Client.Api
/// Initializes a new instance of the <see cref="RecActionApi"/> class. /// Initializes a new instance of the <see cref="RecActionApi"/> class.
/// </summary> /// </summary>
/// <param name="http">The HTTP client used for requests.</param> /// <param name="http">The HTTP client used for requests.</param>
public RecActionApi(HttpClient http) : base(http, "api/RecAction") /// <param name="logger">An optional logger used to record API call outcomes.</param>
#if NETFRAMEWORK
public RecActionApi(HttpClient http, ILogger logger = null) : base(http, "api/RecAction", logger)
#else
public RecActionApi(HttpClient http, ILogger? logger = null) : base(http, "api/RecAction", logger)
#endif
{ {
} }
@@ -30,7 +36,7 @@ namespace ReC.Client.Api
using (content) using (content)
using (var resp = await Http.PostAsync($"{ResourcePath}/invoke/{profileId}", content, cancellationToken)) using (var resp = await Http.PostAsync($"{ResourcePath}/invoke/{profileId}", content, cancellationToken))
{ {
await ReCClientHelpers.EnsureSuccessAsync(resp, cancellationToken).ConfigureAwait(false); await ReCClientHelpers.HandleResponseAsync(resp, Logger, cancellationToken).ConfigureAwait(false);
} }
} }

View File

@@ -1,6 +1,7 @@
using System.Net.Http; using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace ReC.Client.Api namespace ReC.Client.Api
{ {
@@ -13,7 +14,12 @@ namespace ReC.Client.Api
/// Initializes a new instance of the <see cref="ResultApi"/> class. /// Initializes a new instance of the <see cref="ResultApi"/> class.
/// </summary> /// </summary>
/// <param name="http">The HTTP client used for requests.</param> /// <param name="http">The HTTP client used for requests.</param>
public ResultApi(HttpClient http) : base(http, "api/Result") /// <param name="logger">An optional logger used to record API call outcomes.</param>
#if NETFRAMEWORK
public ResultApi(HttpClient http, ILogger logger = null) : base(http, "api/Result", logger)
#else
public ResultApi(HttpClient http, ILogger? logger = null) : base(http, "api/Result", logger)
#endif
{ {
} }