Refactor ReCClient API for async and DI compatibility
Updated `RecActions.InvokeAsync(...).Sync()` to align with migration guidelines, marking `Sync()` as `[Obsolete]` and recommending `async/await` for asynchronous patterns. Enhanced `BuildStaticClient` methods to include an optional `configureOptions` parameter for flexible `ReCClientOptions` configuration. Added conditional compilation for nullable reference type compatibility across .NET Framework and modern .NET versions. Updated `Services.AddRecClient` calls to support `configureOptions`. Retained `[Obsolete]` on static helpers to encourage dependency injection (`services.AddRecClient(...)`) for new code. Revised migration notes to emphasize deprecation of synchronous methods, static helpers, and the importance of adopting modern async and DI patterns. Clarified changes to `GetAsync` methods, error handling with `ReCApiException`, and deserialization behavior.
This commit is contained in:
@@ -431,40 +431,3 @@ Migrations-Tipps:
|
|||||||
|
|
||||||
* **`BuildStaticClient` / `Create`** ? ersetzen durch `services.AddRecClient(...)` und Konstruktor-Injektion.
|
* **`BuildStaticClient` / `Create`** ? ersetzen durch `services.AddRecClient(...)` und Konstruktor-Injektion.
|
||||||
* **`TaskSyncExtensions.Sync`** ? den umliegenden Codepfad asynchron machen (`async Task`) und `await` verwenden.
|
* **`TaskSyncExtensions.Sync`** ? den umliegenden Codepfad asynchron machen (`async Task`) und `await` verwenden.
|
||||||
|
|
||||||
== 7. Migrations-Hinweise (jüngste Änderungen) ==
|
|
||||||
|
|
||||||
Folgende Änderungen sind zu beachten, falls Sie von einer früheren Version migrieren:
|
|
||||||
|
|
||||||
* **GET-Methoden geben jetzt deserialisierte Werte zurück, nicht mehr `HttpResponseMessage`.**
|
|
||||||
** `GetAsync<T>(...)` liest den Body **einmal** und gibt `T?` zurück.
|
|
||||||
** `GetAsync(...)` (ohne Typparameter) gibt `dynamic`/`JsonElement` zurück.
|
|
||||||
** Falls Sie zuvor `HttpResponseMessage` selbst behandelt haben (Status, Body lesen, deserialisieren), entfällt dieser Schritt.
|
|
||||||
* **Einheitliche Fehlerbehandlung über `ReCApiException`.**
|
|
||||||
** Bei HTTP-Fehlern wird konsistent diese Exception geworfen – auch für GET.
|
|
||||||
** Sie müssen nicht mehr selbst auf `IsSuccessStatusCode` prüfen.
|
|
||||||
* **`GetDynamicAsync` wurde umbenannt zu `GetAsync` (Overload).**
|
|
||||||
** Es gibt nun pro API-Klasse zwei `GetAsync`-Overloads: typisiert und dynamisch. Aufrufe von `GetDynamicAsync(...)` müssen zu `GetAsync(...)` geändert werden.
|
|
||||||
* **`TaskSyncExtensions` und statische `ReCClient`-Helfer sind `[Obsolete]`.**
|
|
||||||
|
|
||||||
== 8. FAQ ==
|
|
||||||
|
|
||||||
**Warum gibt `GetAsync<T>` einen deserialisierten Wert statt `HttpResponseMessage` zurück?**
|
|
||||||
|
|
||||||
Damit wird der Response-Body genau einmal gelesen, Fehler werden einheitlich über `ReCApiException` behandelt, und Aufrufer müssen weder selbst auf den Statuscode prüfen noch die Antwort manuell deserialisieren.
|
|
||||||
|
|
||||||
**Wozu der nicht-generische `GetAsync(...)`-Overload?**
|
|
||||||
|
|
||||||
Er ist ein Komfort-Aufruf für Fälle, in denen Sie das Schema nicht (oder noch nicht) typisieren möchten. Intern ruft er `GetAsync<object>` auf und liefert ein `JsonElement` zurück, das Sie ad hoc inspizieren können.
|
|
||||||
|
|
||||||
**Gibt es einen Konflikt zwischen dem generischen und dem nicht-generischen `GetAsync`?**
|
|
||||||
|
|
||||||
Nein. Beide Methoden haben unterschiedliche Signaturen (ein Methodengeneric-Parameter ist Teil der Signatur). Der Compiler wählt anhand der Aufrufsyntax (`GetAsync<T>(...)` vs. `GetAsync(...)`).
|
|
||||||
|
|
||||||
**Soll ich die statischen `ReCClient.Create`-Helfer noch verwenden?**
|
|
||||||
|
|
||||||
Nur in Legacy-Szenarien. Für neuen Code: DI mit `services.AddRecClient(...)`.
|
|
||||||
|
|
||||||
**Sind synchrone Aufrufe via `Sync()` sicher?**
|
|
||||||
|
|
||||||
Nicht generell. In Umgebungen mit `SynchronizationContext` riskieren sie Deadlocks. Verwenden Sie `async/await`.
|
|
||||||
|
|||||||
@@ -93,14 +93,19 @@ namespace ReC.Client
|
|||||||
/// This method should only be called once during application startup.
|
/// This method should only be called once during application startup.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="apiUri">The base URI of the ReC API.</param>
|
/// <param name="apiUri">The base URI of the ReC API.</param>
|
||||||
|
/// <param name="configureOptions">An optional callback to configure <see cref="ReCClientOptions"/>.</param>
|
||||||
/// <exception cref="InvalidOperationException">Thrown if the static provider has already been built.</exception>
|
/// <exception cref="InvalidOperationException">Thrown if the static provider has already been built.</exception>
|
||||||
[Obsolete("Use a local service collection instead of the static provider.")]
|
[Obsolete("Use a local service collection instead of the static provider.")]
|
||||||
public static void BuildStaticClient(string apiUri)
|
#if NETFRAMEWORK
|
||||||
|
public static void BuildStaticClient(string apiUri, Action<ReCClientOptions> configureOptions = null)
|
||||||
|
#else
|
||||||
|
public static void BuildStaticClient(string apiUri, Action<ReCClientOptions>? configureOptions = null)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
if(Provider != null)
|
if(Provider != null)
|
||||||
throw new InvalidOperationException("Static Provider is already built.");
|
throw new InvalidOperationException("Static Provider is already built.");
|
||||||
|
|
||||||
Services.AddRecClient(apiUri);
|
Services.AddRecClient(apiUri, configureOptions);
|
||||||
Provider = Services.BuildServiceProvider();
|
Provider = Services.BuildServiceProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,14 +116,19 @@ namespace ReC.Client
|
|||||||
/// This method should only be called once during application startup.
|
/// This method should only be called once during application startup.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="configureClient">An action to configure the <see cref="HttpClient"/>.</param>
|
/// <param name="configureClient">An action to configure the <see cref="HttpClient"/>.</param>
|
||||||
|
/// <param name="configureOptions">An optional callback to configure <see cref="ReCClientOptions"/>.</param>
|
||||||
/// <exception cref="InvalidOperationException">Thrown if the static provider has already been built.</exception>
|
/// <exception cref="InvalidOperationException">Thrown if the static provider has already been built.</exception>
|
||||||
[Obsolete("Use a local service collection instead of the static provider.")]
|
[Obsolete("Use a local service collection instead of the static provider.")]
|
||||||
public static void BuildStaticClient(Action<HttpClient> configureClient)
|
#if NETFRAMEWORK
|
||||||
|
public static void BuildStaticClient(Action<HttpClient> configureClient, Action<ReCClientOptions> configureOptions = null)
|
||||||
|
#else
|
||||||
|
public static void BuildStaticClient(Action<HttpClient> configureClient, Action<ReCClientOptions>? configureOptions = null)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
if (Provider != null)
|
if (Provider != null)
|
||||||
throw new InvalidOperationException("Static Provider is already built.");
|
throw new InvalidOperationException("Static Provider is already built.");
|
||||||
|
|
||||||
Services.AddRecClient(configureClient);
|
Services.AddRecClient(configureClient, configureOptions);
|
||||||
Provider = Services.BuildServiceProvider();
|
Provider = Services.BuildServiceProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user