Skip to content

Make RestClientContext a record and move logic to RestClientBuilder#129

Merged
twogood merged 4 commits intomainfrom
refactor-rest-context
Oct 25, 2025
Merged

Make RestClientContext a record and move logic to RestClientBuilder#129
twogood merged 4 commits intomainfrom
refactor-rest-context

Conversation

@twogood
Copy link
Owner

@twogood twogood commented Oct 25, 2025

Summary by CodeRabbit

  • New Features

    • Builder option to configure parameter converters.
  • Improvements

    • JSON handling now sets Accept and Content-Type automatically from media types.
    • Header configuration can optionally replace existing entries.
    • Added convenience builder extensions for BaseUri, ContentType and Accept headers.
  • Improvements / API

    • String serializer exposed as a public singleton.
    • Serializer/deserializer Order properties made read-only/immutable.
    • Builder Header signature now supports an optional replace flag.
  • Chores

    • Internal refactor of builder, context and dynamic client; minor test and namespace cleanup; added a no-op request logger.

@twogood twogood self-assigned this Oct 25, 2025
@coderabbitai
Copy link

coderabbitai bot commented Oct 25, 2025

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

📥 Commits

Reviewing files that changed from the base of the PR and between 7d3450e and 38f2b4f.

📒 Files selected for processing (1)
  • Activout.RestClient/Implementation/RestClientBuilder.cs (2 hunks)
 ___________________________________________
< GPU-powered code review. It's the future. >
 -------------------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ

Walkthrough

Reworks RestClient into a non-generic dynamic client, centralizes builder state and attribute handling, makes RestClientContext an immutable record, exposes StringSerializer singleton, tightens serializer/deserializer media-type handling (System.Text.Json & Newtonsoft), adds DummyRequestLogger, and narrows serializer/deserializer Order accessors.

Changes

Cohort / File(s) Summary
Core RestClient refactor
Activout.RestClient/Implementation/RestClient.cs
Replaces generic RestClient<T> with non-generic RestClient(Type, RestClientContext); adds GetDynamicMemberNames(); changes TryInvokeMember to lazy-create/cache RequestHandler instances and invoke Send; streamlines dynamic invocation and nullability.
Builder & lifecycle
Activout.RestClient/Implementation/RestClientBuilder.cs
Rewrites builder to hold private state (base URI, headers, serializers, loggers, factories); adds ContentType, Header (replace semantics), With(IParamConverterManager), attribute parsing (HandleAttributes), Build<T> that assembles RestClientContext and duck-types T.
Context model
Activout.RestClient/Implementation/RestClientContext.cs
Replaces mutable class with immutable internal record RestClientContext(...); parameters become readonly properties; includes computed UseDomainException; file-scoped namespace.
Request logging helper
Activout.RestClient/Implementation/DummyRequestLogger.cs
Adds internal sealed DummyRequestLogger : IRequestLogger, IDisposable with public static IRequestLogger Instance { get; }, TimeOperation(...) returning a no-op disposable, and no-op Dispose().
Header helpers
Activout.RestClient/Implementation/HeaderListExtensions.cs
Makes AddOrReplaceHeader<T> generic over value type, uses OrdinalIgnoreCase for name matching/removal, removes redundant checks, file-scoped namespace and top-level public static class.
Public builder API & extensions
Activout.RestClient/IRestClientBuilder.cs, Activout.RestClient/RestClientBuilderExtensions.cs
Moves IRestClientBuilder to file-scoped namespace, makes it public, adds With(IDuckTyping) and With(IParamConverterManager), updates Header(string, object, bool isReplace = true) signature; introduces top-level RestClientBuilderExtensions with convenience overloads (BaseUri(string), ContentType(string), Accept(string), Header(...)).
String serializer & deserializer changes
Activout.RestClient/Serialization/Implementation/StringSerializer.cs, .../StringDeserializer.cs, .../SerializationManager.cs
Promotes StringSerializer to public sealed and adds public static ISerializer Instance; StringSerializer.Order and StringDeserializer.Order made init-only; CanSerialize uses OrdinalIgnoreCase; DefaultSerializers uses StringSerializer.Instance.
Serializer/Deserializer interfaces
Activout.RestClient/Serialization/ISerializer.cs, Activout.RestClient/Serialization/IDeserializer.cs
Moves interfaces to top-level file-scoped namespace and makes Order read-only (int Order { get; }).
JSON / Newtonsoft extensions
Activout.RestClient.Json/RestClientBuilderJsonExtensions.cs, Activout.RestClient.Newtonsoft.Json/RestClientBuilderNewtonsoftJsonExtensions.cs
Renames supportedMediaTypesmediaTypes, defaults mediaTypes when null, configures serializer/deserializer using resolved media types; sets Accept header to comma-separated media types and ContentType to first media type; Newtonsoft extension uses static defaults and sets Accept/ContentType similarly.
Tests & minor cleanup
Activout.RestClient.Newtonsoft.Json.Test/RestClientTests.cs, Activout.RestClient.Newtonsoft.Json.Test/NewtonsoftJsonDeserializerTest.cs
Removes unused using; replaces lambda parameter name with _ in mock response; renames test method to TestCamelCaseSerializerSettings.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Caller (dynamic call)
    participant Rest as RestClient
    participant Binder as InvokeMemberBinder
    participant Cache as _requestHandlers
    participant Factory as RequestHandler (factory)
    participant Handler as RequestHandler.Send

    Client->>Rest: dynamicMethod(...) 
    Rest->>Binder: TryInvokeMember(binder, args)
    Rest->>Cache: lookup binder.Name
    alt handler cached
        Cache-->>Rest: cached handler
        Rest->>Handler: cached.Send(args)
    else not cached
        Rest->>Factory: new RequestHandler(binder,...)
        Factory->>Cache: cache handler
        rect rgb(220,245,220)
            Rest->>Handler: new.Send(args)
        end
    end
    Handler-->>Client: result / Task
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Focus review on:
    • RestClient.cs — dynamic invocation, caching correctness, thread-safety, nullability.
    • RestClientBuilder.cs & RestClientContext.cs — correct defaults, attribute handling, immutability and construction of context.
    • IRestClientBuilder signature changes and Header replace semantics for API compatibility.
    • JSON/Newtonsoft extensions — media-type resolution and header behavior.

Possibly related PRs

  • Nullable Serialization #128 — touches StringSerializer null-handling and serialize behavior; likely related to the singleton/exposed serializer change.

Poem

A rabbit refactors, quick and keen, 🐇
Types untangled, builders wiped clean,
Handlers cached and serializers bright,
Dummy logs hush the quiet night,
New media types shine — hop, code takes flight! 🎉

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 1.72% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "Make RestClientContext a record and move logic to RestClientBuilder" accurately captures the core architectural refactoring present in this changeset. The summary confirms that RestClientContext was converted from a mutable class to an immutable record with a parameterized constructor, and RestClientBuilder underwent a substantial rewrite with field-driven state management that now assembles the RestClientContext internally. These two interconnected changes form the primary architectural transformation of the PR. While the changeset includes several supporting modifications (RestClient refactoring, serialization interface updates, and extension method changes), the title appropriately focuses on the main structural change without attempting to enumerate every detail, which aligns with the principle that titles don't need to cover all aspects of a changeset.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (14)
Activout.RestClient/Serialization/Implementation/StringSerializer.cs (2)

12-15: Case-insensitive match and expression-bodied members.

Media types are case-insensitive. Also these methods are perfect candidates for expression bodies.

Apply:

-    public HttpContent Serialize(object? data, Encoding encoding, MediaType mediaType)
-    {
-        return new StringContent(data?.ToString() ?? "", encoding, mediaType.Value);
-    }
+    public HttpContent Serialize(object? data, Encoding encoding, MediaType mediaType)
+        => new StringContent(data?.ToString() ?? "", encoding, mediaType.Value);
@@
-    public bool CanSerialize(MediaType mediaType)
-    {
-        return mediaType.Value.StartsWith("text/");
-    }
+    public bool CanSerialize(MediaType mediaType)
+        => mediaType.Value.StartsWith("text/", StringComparison.OrdinalIgnoreCase);

As per coding guidelines.

Also applies to: 17-20


6-6: Consider sealing the type.

If inheritance isn’t required, seal for clarity and minor JIT optimizations.

-public class StringSerializer : ISerializer
+public sealed class StringSerializer : ISerializer
Activout.RestClient/Implementation/DummyRequestLogger.cs (1)

10-18: Use expression-bodied members.

Tiny no-op logger; simplify.

-    public IDisposable TimeOperation(HttpRequestMessage httpRequestMessage)
-    {
-        return this;
-    }
+    public IDisposable TimeOperation(HttpRequestMessage httpRequestMessage) => this;
@@
-    public void Dispose()
-    {
-        // Do nothing
-    }
+    public void Dispose() { /* no-op */ }

As per coding guidelines.

Activout.RestClient.Newtonsoft.Json/RestClientBuilderNewtonsoftJsonExtensions.cs (1)

11-17: Avoid First() when media type list could be empty.

Be defensive; set Accept regardless, set Content-Type only when a first exists.

-        var settings = jsonSerializerSettings ?? DefaultJsonSerializerSettings;
+        var settings = jsonSerializerSettings ?? DefaultJsonSerializerSettings;
@@
-        builder.Accept(string.Join(", ", SupportedMediaTypes.Select(type => type.Value)));
-        builder.ContentType(SupportedMediaTypes.First());
+        var accept = string.Join(", ", SupportedMediaTypes.Select(type => type.Value));
+        builder.Accept(accept);
+        var first = SupportedMediaTypes.FirstOrDefault();
+        if (first is not null)
+        {
+            builder.ContentType(first);
+        }
Activout.RestClient.Json/RestClientBuilderJsonExtensions.cs (1)

22-27: Guard against empty media types.

Avoid First() on an empty array; fail fast or skip setting Content-Type.

-        mediaTypes ??= MediaTypes;
+        mediaTypes ??= MediaTypes;
+        if (mediaTypes.Length == 0)
+            throw new ArgumentException("At least one media type is required.", nameof(mediaTypes));
@@
-        builder.Accept(string.Join(", ", mediaTypes.Select(type => type.Value)));
-        builder.ContentType(mediaTypes.First());
+        builder.Accept(string.Join(", ", mediaTypes.Select(type => type.Value)));
+        builder.ContentType(mediaTypes[0]);

As per coding guidelines.

Activout.RestClient/Implementation/RestClientBuilder.cs (4)

35-35: Use collection expressions for empty list initialization.

Modern C#: prefer [] over new List().

-    private List<KeyValuePair<string, object>> _defaultHeaders = new List<KeyValuePair<string, object>>();
+    private List<KeyValuePair<string, object>> _defaultHeaders = [];

As per coding guidelines.


52-56: Avoid duplicate default headers.

Use AddOrReplace to prevent repeated entries for the same header.

-        _defaultHeaders.Add(new KeyValuePair<string, object>(name, value));
+        _defaultHeaders.AddOrReplaceHeader(name, value, replace: true);

Based on helpers in Activout.RestClient.Implementation.HeaderListExtensions.


174-184: Minor: tighten AddTrailingSlash.

Use char EndsWith and string interpolation for small clarity/perf wins.

-    private static Uri AddTrailingSlash(Uri apiUri)
+    private static Uri AddTrailingSlash(Uri apiUri)
     {
         var uriBuilder = new UriBuilder(apiUri ?? throw new ArgumentNullException(nameof(apiUri)));
-        if (uriBuilder.Path.EndsWith("/"))
+        if (uriBuilder.Path.EndsWith('/'))
         {
             return apiUri;
         }
 
-        uriBuilder.Path = uriBuilder.Path + "/";
+        uriBuilder.Path = $"{uriBuilder.Path}/";
         return uriBuilder.Uri;
     }

As per coding guidelines.


151-172: Consider inheritable attributes (optional).

If attributes can be declared on base interfaces/types, use GetCustomAttributes(inherit: true).

-        var attributes = type.GetCustomAttributes();
+        var attributes = type.GetCustomAttributes(inherit: true);

Please confirm whether attribute inheritance is desired for your API surface.

Activout.RestClient/Implementation/RestClientContext.cs (2)

12-26: DefaultHeaders should be immutable at the API surface

This record models immutable config, but DefaultHeaders is List<...>, which is mutable. Expose it as IReadOnlyList<...> to preserve immutability and thread-safety while keeping current usages (e.g., AddRange) intact.

As per coding guidelines.

-    List<KeyValuePair<string, object>> DefaultHeaders,
+    IReadOnlyList<KeyValuePair<string, object>> DefaultHeaders,

28-28: Use expression-bodied property for the simple computed member

Tiny polish to align with the guideline on expression-bodied members.

As per coding guidelines.

-    public bool UseDomainException { get; } = DomainExceptionType != null;
+    public bool UseDomainException => DomainExceptionType != null;
Activout.RestClient/Implementation/RestClient.cs (3)

15-16: Use GetOrAdd to avoid duplicate handler creation under concurrency

You already use ConcurrentDictionary; switching the field type and using GetOrAdd removes the create-then-assign race and simplifies code.

-    private readonly IDictionary<MethodInfo, RequestHandler> _requestHandlers =
-        new ConcurrentDictionary<MethodInfo, RequestHandler>();
+    private readonly ConcurrentDictionary<MethodInfo, RequestHandler> _requestHandlers = new();
-        if (!_requestHandlers.TryGetValue(method, out var requestHandler))
-        {
-            requestHandler = new RequestHandler(method, _context);
-            _requestHandlers[method] = requestHandler;
-        }
+        var requestHandler = _requestHandlers.GetOrAdd(method, m => new RequestHandler(m, _context));

Also applies to: 38-42


24-27: Minor tidy: expression-bodied + distinct names

Keeps it concise and avoids duplicate member names for better dynamic tooling hints.

As per coding guidelines.

-    public override IEnumerable<string> GetDynamicMemberNames()
-    {
-        return _type.GetMembers().Select(x => x.Name);
-    }
+    public override IEnumerable<string> GetDynamicMemberNames() =>
+        _type.GetMembers().Select(x => x.Name).Distinct();

10-22: Guardrails (optional): validate constructor inputs

If type or context is ever null, later reflection/dispatch will NRE. Consider simple guards to fail fast.

-    public RestClient(Type type, RestClientContext context)
+    public RestClient(Type type, RestClientContext context)
     {
-        _type = type;
-        _context = context;
+        _type = type ?? throw new ArgumentNullException(nameof(type));
+        _context = context ?? throw new ArgumentNullException(nameof(context));
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6663fdc and 2f98349.

📒 Files selected for processing (8)
  • Activout.RestClient.Json/RestClientBuilderJsonExtensions.cs (2 hunks)
  • Activout.RestClient.Newtonsoft.Json.Test/RestClientTests.cs (1 hunks)
  • Activout.RestClient.Newtonsoft.Json/RestClientBuilderNewtonsoftJsonExtensions.cs (2 hunks)
  • Activout.RestClient/Implementation/DummyRequestLogger.cs (1 hunks)
  • Activout.RestClient/Implementation/RestClient.cs (1 hunks)
  • Activout.RestClient/Implementation/RestClientBuilder.cs (2 hunks)
  • Activout.RestClient/Implementation/RestClientContext.cs (1 hunks)
  • Activout.RestClient/Serialization/Implementation/StringSerializer.cs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.cs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.cs: Use [] list syntax for collections
Use file-scoped namespaces
Use primary constructors wherever possible
Use records for data transfer objects (DTOs) and immutable data structures
Use var for local variable declarations when possible
Use expression-bodied members for simple methods and properties
Use pattern matching for type checks and deconstruction
Use using statements for resource management
Use async and await for asynchronous programming
Never include "Async" in method names
Only include comments that explain why something is done, not what is done

Files:

  • Activout.RestClient/Implementation/DummyRequestLogger.cs
  • Activout.RestClient.Newtonsoft.Json.Test/RestClientTests.cs
  • Activout.RestClient.Json/RestClientBuilderJsonExtensions.cs
  • Activout.RestClient.Newtonsoft.Json/RestClientBuilderNewtonsoftJsonExtensions.cs
  • Activout.RestClient/Implementation/RestClient.cs
  • Activout.RestClient/Implementation/RestClientBuilder.cs
  • Activout.RestClient/Implementation/RestClientContext.cs
  • Activout.RestClient/Serialization/Implementation/StringSerializer.cs
🧬 Code graph analysis (6)
Activout.RestClient.Json/RestClientBuilderJsonExtensions.cs (5)
Activout.RestClient.Json/SystemTextJsonDefaults.cs (1)
  • SystemTextJsonDefaults (43-49)
Activout.RestClient.Newtonsoft.Json/RestClientBuilderNewtonsoftJsonExtensions.cs (1)
  • IRestClientBuilder (8-19)
Activout.RestClient/Implementation/RestClientBuilder.cs (13)
  • IRestClientBuilder (40-44)
  • IRestClientBuilder (46-50)
  • IRestClientBuilder (52-56)
  • IRestClientBuilder (58-62)
  • IRestClientBuilder (64-68)
  • IRestClientBuilder (70-74)
  • IRestClientBuilder (76-80)
  • IRestClientBuilder (82-86)
  • IRestClientBuilder (88-92)
  • IRestClientBuilder (94-98)
  • IRestClientBuilder (100-104)
  • IRestClientBuilder (106-110)
  • IRestClientBuilder (112-116)
Activout.RestClient.Json/SystemTextJsonSerializer.cs (1)
  • SystemTextJsonSerializer (11-48)
Activout.RestClient.Json/SystemTextJsonDeserializer.cs (1)
  • SystemTextJsonDeserializer (9-52)
Activout.RestClient.Newtonsoft.Json/RestClientBuilderNewtonsoftJsonExtensions.cs (2)
Activout.RestClient.Newtonsoft.Json/NewtonsoftJsonSerializer.cs (2)
  • NewtonsoftJsonSerializer (7-31)
  • NewtonsoftJsonSerializer (13-16)
Activout.RestClient.Newtonsoft.Json/NewtonsoftJsonDeserializer.cs (2)
  • NewtonsoftJsonDeserializer (7-39)
  • NewtonsoftJsonDeserializer (13-16)
Activout.RestClient/Implementation/RestClient.cs (1)
Activout.RestClient/Implementation/RequestHandler.cs (4)
  • Type (151-158)
  • RequestHandler (20-575)
  • RequestHandler (45-113)
  • Send (194-240)
Activout.RestClient/Implementation/RestClientBuilder.cs (10)
Activout.RestClient/Implementation/RestClient.cs (2)
  • RestClient (10-47)
  • RestClient (18-22)
Activout.RestClient/MediaType.cs (2)
  • MediaType (8-11)
  • MediaType (15-22)
Activout.RestClient/Helpers/Implementation/DuckTyping.cs (1)
  • DuckTyping (5-13)
Activout.RestClient/Serialization/Implementation/SerializationManager.cs (4)
  • ISerializer (43-47)
  • SerializationManager (8-48)
  • SerializationManager (30-35)
  • IDeserializer (37-41)
Activout.RestClient/Helpers/Implementation/TaskConverter3Factory.cs (1)
  • TaskConverter3Factory (5-15)
Activout.RestClient/ParamConverter/Implementation/ParamConverterManager.cs (2)
  • ParamConverterManager (7-31)
  • ParamConverterManager (13-17)
Activout.RestClient/Implementation/DummyRequestLogger.cs (1)
  • DummyRequestLogger (6-19)
Activout.RestClient/ContentTypeAttribute.cs (1)
  • ContentTypeAttribute (10-13)
Activout.RestClient/DomainExceptions/DomainExceptionAttribute.cs (1)
  • DomainExceptionAttribute (10-18)
Activout.RestClient/Implementation/HeaderListExtensions.cs (1)
  • AddOrReplaceHeader (8-18)
Activout.RestClient/Implementation/RestClientContext.cs (1)
Activout.RestClient/Implementation/RestClient.cs (2)
  • RestClient (10-47)
  • RestClient (18-22)
Activout.RestClient/Serialization/Implementation/StringSerializer.cs (3)
Activout.RestClient/Serialization/Implementation/SerializationManager.cs (1)
  • ISerializer (43-47)
Activout.RestClient/Serialization/ISerializer.cs (2)
  • HttpContent (9-9)
  • CanSerialize (10-10)
Activout.RestClient/Implementation/RequestHandler.cs (2)
  • HttpContent (427-434)
  • HttpContent (436-449)
🔇 Additional comments (3)
Activout.RestClient.Newtonsoft.Json.Test/RestClientTests.cs (1)

93-93: LGTM! Good use of discard pattern.

Using _ for the unused lambda parameter explicitly indicates it's intentionally unused, which improves code clarity and is consistent with the pattern at line 76.

Activout.RestClient.Newtonsoft.Json/RestClientBuilderNewtonsoftJsonExtensions.cs (1)

1-3: Remove the suggestion to add using System.Linq;—LINQ is already available via implicit usings.

The project has <ImplicitUsings>enable</ImplicitUsings> configured for net8.0, which automatically includes System.Linq without an explicit import. The .Select() and .First() calls work correctly as-is. No changes needed.

Likely an incorrect or invalid review comment.

Activout.RestClient.Json/RestClientBuilderJsonExtensions.cs (1)

1-3: LINQ import is not needed; System.Linq is already available through ImplicitUsings.

With .NET 8.0 and <ImplicitUsings>enable</ImplicitUsings> configured in the project file, System.Linq is automatically included globally. The code uses Select() and First() methods without issue, confirming that the namespace is in scope through implicit usings rather than explicit import.

Likely an incorrect or invalid review comment.

Comment on lines +31 to 36
var method = _type.GetMethod(binder.Name);
if (method == null)
{
return _type.GetMembers().Select(x => x.Name);
result = null;
return false;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix overload resolution to avoid AmbiguousMatchException and wrong method dispatch

_type.GetMethod(binder.Name) throws for overloaded methods and ignores argument shapes. Resolve by selecting the best candidate using argument count/types (and allowing a trailing CancellationToken).

Apply this diff to use a resolver:

-        var method = _type.GetMethod(binder.Name);
-        if (method == null)
+        var method = ResolveMethod(binder.Name, args);
+        if (method is null)
         {
             result = null;
             return false;
         }

Add this helper inside the class:

private MethodInfo? ResolveMethod(string name, object?[]? args)
{
    var candidates = _type.GetMethods(BindingFlags.Public | BindingFlags.Instance)
                          .Where(m => m.Name == name)
                          .ToArray();

    if (candidates.Length == 0) return null;

    var argArray = args as object[] ?? Array.Empty<object>();
    var argCount = argArray.Length;

    foreach (var m in candidates)
    {
        var ps = m.GetParameters();
        var hasCt = ps.Length > 0 && ps[^1].ParameterType == typeof(System.Threading.CancellationToken);
        var matchCount = hasCt ? ps.Length - 1 : ps.Length;
        if (matchCount != argCount) continue;

        var ok = true;
        for (var i = 0; i < matchCount; i++)
        {
            var a = argArray[i];
            if (a is null) continue; // null is acceptable for ref/nullable params
            if (!ps[i].ParameterType.IsInstanceOfType(a)) { ok = false; break; }
        }
        if (ok) return m;
    }

    // Fallback: first by name
    return candidates.FirstOrDefault();
}

And add the needed using:

 using System.Reflection;
+using System.Threading;
🤖 Prompt for AI Agents
In Activout.RestClient/Implementation/RestClient.cs around lines 31 to 36, the
current call to _type.GetMethod(binder.Name) fails for overloaded methods and
ignores argument shapes; add a ResolveMethod helper (as described in the review)
inside the class to pick the correct MethodInfo by filtering candidates by name,
parameter count/types and allowing a trailing CancellationToken, replace the
direct GetMethod call with ResolveMethod(binder.Name, args) (or similar) so you
select the best overload, and add the required using for BindingFlags/Reflection
at the top of the file.

Comment on lines +44 to +45
result = requestHandler.Send(args);
return true;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Null-safe handoff of args to RequestHandler.Send(object[])

TryInvokeMember receives object?[]?; RequestHandler.Send expects object[]. Coalesce to an empty array at the call site.

-        result = requestHandler.Send(args);
+        result = requestHandler.Send((args as object[]) ?? Array.Empty<object>());
         return true;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
result = requestHandler.Send(args);
return true;
result = requestHandler.Send((args as object[]) ?? Array.Empty<object>());
return true;
🤖 Prompt for AI Agents
In Activout.RestClient/Implementation/RestClient.cs around lines 44-45,
TryInvokeMember receives a nullable object?[]? named args but
RequestHandler.Send expects a non-null object[]; coalesce args to
Array.Empty<object>() (or new object[0]) at the call site so you pass a non-null
empty array when args is null, and then call requestHandler.Send with that
coalesced array.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (7)
Activout.RestClient/Implementation/DummyRequestLogger.cs (2)

6-6: Consider making the constructor private to enforce the singleton pattern.

While the class is already internal sealed, making the constructor private would more explicitly communicate that direct instantiation is not intended and the Instance property should be used.

Apply this diff to add a private constructor:

 internal sealed class DummyRequestLogger : IRequestLogger, IDisposable
 {
+    private DummyRequestLogger() { }
+
     public static IRequestLogger Instance { get; } = new DummyRequestLogger();

12-15: Consider removing the comment.

The comment explains what the code does (nothing) rather than why, which doesn't align with the coding guideline. Since the method body is empty, it's self-evident that it does nothing.

As per coding guidelines.

Apply this diff to remove the comment:

     public void Dispose()
     {
-        // Do nothing
     }
Activout.RestClient/Serialization/Implementation/StringSerializer.cs (2)

11-11: Avoid singleton-wide side effects from mutable Order.

If callers mutate Order on the shared Instance, it affects all clients. Prefer making Order immutable (if the ISerializer contract allows) or ensure consumers don’t adjust it.

Example:

-    public int Order { get; set; } = 1000;
+    public int Order { get; } = 1000;

If ISerializer requires a setter, consider not exposing a singleton for configurable instances and use the singleton only with a fixed order.


7-18: Use the singleton consistently in defaults.

SerializationManager.DefaultSerializers still constructs a new StringSerializer(). To avoid duplicate instances and ensure consistent ordering, switch it to StringSerializer.Instance.

Change in Activout.RestClient/Serialization/Implementation/SerializationManager.cs:

-            new FormUrlEncodedSerializer(),
-            new StringSerializer(),
-            new ByteArraySerializer()
+            new FormUrlEncodedSerializer(),
+            StringSerializer.Instance,
+            new ByteArraySerializer()
Activout.RestClient/IRestClientBuilder.cs (1)

1-1: Enable nullable on the public surface.

Public API should ship with nullable enabled for better consumers’ experience.

-#nullable disable
+#nullable enable
Activout.RestClient/Implementation/HeaderListExtensions.cs (1)

8-18: LGTM; consider argument guards as a small hardening.

Current logic is fine. Optionally add null checks to fail fast.

 public static void AddOrReplaceHeader<T>(this List<KeyValuePair<string, T>> headers, string name,
     T value, bool replace)
 {
-    if (replace)
+    if (headers == null) throw new ArgumentNullException(nameof(headers));
+    if (name == null) throw new ArgumentNullException(nameof(name));
+    if (replace)
     {
         headers.RemoveAll(header =>
             header.Key.Equals(name, StringComparison.OrdinalIgnoreCase));
     }
 
     headers.Add(new KeyValuePair<string, T>(name, value));
 }
Activout.RestClient/Implementation/RestClientBuilder.cs (1)

118-147: HttpClient lifetime consideration.

Creating a new HttpClient per Build when none is supplied can lead to socket exhaustion in some usage patterns. Prefer requiring an HttpClient or integrating with IHttpClientFactory in hosting scenarios.

If keeping the fallback, document usage and recommend passing a shared HttpClient from the app layer.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2f98349 and 7395441.

📒 Files selected for processing (6)
  • Activout.RestClient/IRestClientBuilder.cs (1 hunks)
  • Activout.RestClient/Implementation/DummyRequestLogger.cs (1 hunks)
  • Activout.RestClient/Implementation/HeaderListExtensions.cs (1 hunks)
  • Activout.RestClient/Implementation/RestClientBuilder.cs (2 hunks)
  • Activout.RestClient/Implementation/RestClientContext.cs (1 hunks)
  • Activout.RestClient/Serialization/Implementation/StringSerializer.cs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.cs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.cs: Use [] list syntax for collections
Use file-scoped namespaces
Use primary constructors wherever possible
Use records for data transfer objects (DTOs) and immutable data structures
Use var for local variable declarations when possible
Use expression-bodied members for simple methods and properties
Use pattern matching for type checks and deconstruction
Use using statements for resource management
Use async and await for asynchronous programming
Never include "Async" in method names
Only include comments that explain why something is done, not what is done

Files:

  • Activout.RestClient/Implementation/RestClientBuilder.cs
  • Activout.RestClient/Implementation/RestClientContext.cs
  • Activout.RestClient/Implementation/HeaderListExtensions.cs
  • Activout.RestClient/Implementation/DummyRequestLogger.cs
  • Activout.RestClient/Serialization/Implementation/StringSerializer.cs
  • Activout.RestClient/IRestClientBuilder.cs
🧬 Code graph analysis (5)
Activout.RestClient/Implementation/RestClientBuilder.cs (10)
Activout.RestClient/Implementation/RestClient.cs (2)
  • RestClient (10-47)
  • RestClient (18-22)
Activout.RestClient/IRestClientBuilder.cs (12)
  • IRestClientBuilder (13-13)
  • IRestClientBuilder (14-14)
  • IRestClientBuilder (15-15)
  • IRestClientBuilder (16-16)
  • IRestClientBuilder (17-17)
  • IRestClientBuilder (18-18)
  • IRestClientBuilder (19-19)
  • IRestClientBuilder (20-20)
  • IRestClientBuilder (21-21)
  • IRestClientBuilder (22-22)
  • IRestClientBuilder (23-23)
  • T (24-24)
Activout.RestClient/MediaType.cs (2)
  • MediaType (8-11)
  • MediaType (15-22)
Activout.RestClient/Helpers/Implementation/DuckTyping.cs (1)
  • DuckTyping (5-13)
Activout.RestClient/Serialization/Implementation/SerializationManager.cs (4)
  • ISerializer (43-47)
  • SerializationManager (8-48)
  • SerializationManager (30-35)
  • IDeserializer (37-41)
Activout.RestClient/ParamConverter/Implementation/ParamConverterManager.cs (2)
  • ParamConverterManager (7-31)
  • ParamConverterManager (13-17)
Activout.RestClient/Implementation/DummyRequestLogger.cs (1)
  • DummyRequestLogger (6-16)
Activout.RestClient/ContentTypeAttribute.cs (1)
  • ContentTypeAttribute (10-13)
Activout.RestClient/DomainExceptions/DomainExceptionAttribute.cs (1)
  • DomainExceptionAttribute (10-18)
Activout.RestClient/HeaderAttribute.cs (1)
  • HeaderAttribute (12-17)
Activout.RestClient/Implementation/RestClientContext.cs (5)
Activout.RestClient/Implementation/RestClient.cs (2)
  • RestClient (10-47)
  • RestClient (18-22)
Activout.RestClient/Serialization/ISerializationManager.cs (1)
  • ISerializer (5-5)
Activout.RestClient/Serialization/Implementation/SerializationManager.cs (3)
  • ISerializer (43-47)
  • SerializationManager (8-48)
  • SerializationManager (30-35)
Activout.RestClient/MediaType.cs (2)
  • MediaType (8-11)
  • MediaType (15-22)
Activout.RestClient/ParamConverter/Implementation/ParamConverterManager.cs (2)
  • ParamConverterManager (7-31)
  • ParamConverterManager (13-17)
Activout.RestClient/Implementation/HeaderListExtensions.cs (1)
Activout.RestClient/Implementation/RestClientBuilder.cs (1)
  • T (118-147)
Activout.RestClient/Serialization/Implementation/StringSerializer.cs (4)
Activout.RestClient/Serialization/Implementation/SerializationManager.cs (1)
  • ISerializer (43-47)
Activout.RestClient/Serialization/ISerializer.cs (2)
  • HttpContent (9-9)
  • CanSerialize (10-10)
Activout.RestClient/Implementation/RequestHandler.cs (2)
  • HttpContent (427-434)
  • HttpContent (436-449)
Activout.RestClient/MediaType.cs (3)
  • MediaType (8-11)
  • MediaType (15-22)
  • ToString (24-27)
Activout.RestClient/IRestClientBuilder.cs (3)
Activout.RestClient/Implementation/RestClient.cs (2)
  • RestClient (10-47)
  • RestClient (18-22)
Activout.RestClient/Implementation/RestClientBuilder.cs (15)
  • IRestClientBuilder (40-44)
  • IRestClientBuilder (46-50)
  • IRestClientBuilder (52-56)
  • IRestClientBuilder (58-62)
  • IRestClientBuilder (64-68)
  • IRestClientBuilder (70-74)
  • IRestClientBuilder (76-80)
  • IRestClientBuilder (82-86)
  • IRestClientBuilder (88-92)
  • IRestClientBuilder (94-98)
  • IRestClientBuilder (100-104)
  • IRestClientBuilder (106-110)
  • IRestClientBuilder (112-116)
  • Uri (174-184)
  • T (118-147)
Activout.RestClient/IRestClientFactory.cs (1)
  • IRestClientBuilder (6-6)
🔇 Additional comments (2)
Activout.RestClient/Implementation/DummyRequestLogger.cs (1)

6-15: LGTM! Clean singleton no-op logger implementation.

The implementation is correct and efficient:

  • Thread-safe singleton pattern using static property initialization
  • Returning this from TimeOperation is an acceptable optimization for a no-op logger, avoiding unnecessary allocations
  • Expression-bodied members and file-scoped namespace align with coding guidelines
Activout.RestClient/Implementation/RestClientContext.cs (1)

12-29: Immutable context snapshot looks good.

Record parameters and IReadOnlyList headers align with immutability goals.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
Activout.RestClient/Implementation/RestClientBuilder.cs (2)

163-163: Nice: defensive copy of headers preserves context immutability.

Prevents later builder mutations from affecting built clients. Matches the “record context” intent.


192-196: Guard against empty/whitespace PathAttribute.Template.

Prevents accidental empty base templates.

-                case PathAttribute pathAttribute:
-                    if (pathAttribute.Template != null)
-                    {
-                        _baseTemplate = pathAttribute.Template;
-                    }
+                case PathAttribute pathAttribute:
+                    if (!string.IsNullOrWhiteSpace(pathAttribute.Template))
+                    {
+                        _baseTemplate = pathAttribute.Template;
+                    }
🧹 Nitpick comments (6)
Activout.RestClient/Serialization/Implementation/StringDeserializer.cs (1)

19-22: Consider using expression-bodied syntax for simple method.

The method contains a single expression and could be more concise with expression-bodied syntax. As per coding guidelines.

Apply this diff:

-    public bool CanDeserialize(MediaType mediaType)
-    {
-        return mediaType.Value.StartsWith("text/");
-    }
+    public bool CanDeserialize(MediaType mediaType) => 
+        mediaType.Value.StartsWith("text/");
Activout.RestClient/Serialization/Implementation/SerializationManager.cs (1)

10-16: Adopt collection expressions ([]) to match project guidelines.

Simplify defaults with C# collection expressions for readability and consistency.

Apply:

-    public static readonly IReadOnlyCollection<ISerializer> DefaultSerializers = new List<ISerializer>
-        {
-            new FormUrlEncodedSerializer(),
-            StringSerializer.Instance,
-            new ByteArraySerializer()
-        }
-        .ToImmutableList();
+    public static readonly IReadOnlyCollection<ISerializer> DefaultSerializers =
+        [ new FormUrlEncodedSerializer(), StringSerializer.Instance, new ByteArraySerializer() ]
+        .ToImmutableList();

-    public static readonly IReadOnlyCollection<IDeserializer> DefaultDeserializers =
-        new List<IDeserializer>
-            {
-                new StringDeserializer(),
-                new ByteArrayDeserializer()
-            }
-            .ToImmutableList();
+    public static readonly IReadOnlyCollection<IDeserializer> DefaultDeserializers =
+        [ new StringDeserializer(), new ByteArrayDeserializer() ]
+        .ToImmutableList();

As per coding guidelines.

Also applies to: 18-24

Activout.RestClient/RestClientBuilderExtensions.cs (2)

8-27: Use expression-bodied members for one-liners.

Keeps extensions terse and idiomatic.

-    public static IRestClientBuilder BaseUri(this IRestClientBuilder self, string apiUri)
-    {
-        return self.BaseUri(new Uri(apiUri));
-    }
+    public static IRestClientBuilder BaseUri(this IRestClientBuilder self, string apiUri) =>
+        self.BaseUri(new Uri(apiUri));

-    public static IRestClientBuilder ContentType(this IRestClientBuilder self, string contentType)
-    {
-        return self.ContentType(new MediaType(contentType));
-    }
+    public static IRestClientBuilder ContentType(this IRestClientBuilder self, string contentType) =>
+        self.ContentType(new MediaType(contentType));

-    public static IRestClientBuilder Accept(this IRestClientBuilder self, string accept)
-    {
-        return self.Header("Accept", accept);
-    }
+    public static IRestClientBuilder Accept(this IRestClientBuilder self, string accept) =>
+        self.Header("Accept", accept);

-    public static IRestClientBuilder Header(this IRestClientBuilder self,
-        AuthenticationHeaderValue authenticationHeaderValue)
-    {
-        return self.Header("Authorization", authenticationHeaderValue);
-    }
+    public static IRestClientBuilder Header(this IRestClientBuilder self,
+        AuthenticationHeaderValue authenticationHeaderValue) =>
+        self.Header("Authorization", authenticationHeaderValue);

As per coding guidelines.


23-27: Name the Authorization helper explicitly.

Method name Header(AuthenticationHeaderValue) is vague and easy to confuse with Header(name,value). Consider renaming to Authorization to clarify intent.

-    public static IRestClientBuilder Header(this IRestClientBuilder self,
+    public static IRestClientBuilder Authorization(this IRestClientBuilder self,
         AuthenticationHeaderValue authenticationHeaderValue) =>
         self.Header("Authorization", authenticationHeaderValue);
Activout.RestClient/Implementation/RestClientBuilder.cs (2)

161-165: Use singleton DefaultDomainExceptionMapperFactory.Instance.

Avoid unnecessary allocations; align with other singletons (DuckTyping, ParamConverterManager, DummyRequestLogger).

-            DomainExceptionMapperFactory: _domainExceptionMapperFactory ??
-                                          new DefaultDomainExceptionMapperFactory(),
+            DomainExceptionMapperFactory: _domainExceptionMapperFactory ??
+                                          DefaultDomainExceptionMapperFactory.Instance,

155-156: Operational note: consider HttpClient lifetime.

Defaulting to new HttpClient per Build can increase socket pressure in apps that build many clients. Encourage consumers to pass a shared HttpClient (e.g., via HttpClientFactory), or consider an optional static default.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7395441 and 7d3450e.

📒 Files selected for processing (10)
  • Activout.RestClient.Newtonsoft.Json.Test/NewtonsoftJsonDeserializerTest.cs (4 hunks)
  • Activout.RestClient/IRestClientBuilder.cs (1 hunks)
  • Activout.RestClient/Implementation/DummyRequestLogger.cs (1 hunks)
  • Activout.RestClient/Implementation/RestClientBuilder.cs (2 hunks)
  • Activout.RestClient/RestClientBuilderExtensions.cs (1 hunks)
  • Activout.RestClient/Serialization/IDeserializer.cs (1 hunks)
  • Activout.RestClient/Serialization/ISerializer.cs (1 hunks)
  • Activout.RestClient/Serialization/Implementation/SerializationManager.cs (2 hunks)
  • Activout.RestClient/Serialization/Implementation/StringDeserializer.cs (1 hunks)
  • Activout.RestClient/Serialization/Implementation/StringSerializer.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • Activout.RestClient/Serialization/Implementation/StringSerializer.cs
  • Activout.RestClient/Implementation/DummyRequestLogger.cs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.cs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.cs: Use [] list syntax for collections
Use file-scoped namespaces
Use primary constructors wherever possible
Use records for data transfer objects (DTOs) and immutable data structures
Use var for local variable declarations when possible
Use expression-bodied members for simple methods and properties
Use pattern matching for type checks and deconstruction
Use using statements for resource management
Use async and await for asynchronous programming
Never include "Async" in method names
Only include comments that explain why something is done, not what is done

Files:

  • Activout.RestClient/Serialization/ISerializer.cs
  • Activout.RestClient.Newtonsoft.Json.Test/NewtonsoftJsonDeserializerTest.cs
  • Activout.RestClient/Implementation/RestClientBuilder.cs
  • Activout.RestClient/Serialization/IDeserializer.cs
  • Activout.RestClient/Serialization/Implementation/SerializationManager.cs
  • Activout.RestClient/Serialization/Implementation/StringDeserializer.cs
  • Activout.RestClient/IRestClientBuilder.cs
  • Activout.RestClient/RestClientBuilderExtensions.cs
🧬 Code graph analysis (8)
Activout.RestClient/Serialization/ISerializer.cs (5)
Activout.RestClient/Serialization/Implementation/SerializationManager.cs (1)
  • ISerializer (43-47)
Activout.RestClient.Newtonsoft.Json/NewtonsoftJsonSerializer.cs (2)
  • CanSerialize (27-30)
  • Activout (5-32)
Activout.RestClient.Json/SystemTextJsonSerializer.cs (2)
  • CanSerialize (44-47)
  • SystemTextJsonSerializer (11-48)
Activout.RestClient.Xml/XmlSerializer.cs (2)
  • CanSerialize (29-32)
  • XmlSerializer (7-28)
Activout.RestClient/Serialization/Implementation/ByteArraySerializer.cs (2)
  • CanSerialize (25-28)
  • Activout (6-31)
Activout.RestClient.Newtonsoft.Json.Test/NewtonsoftJsonDeserializerTest.cs (2)
Activout.RestClient.Newtonsoft.Json.Test/RestClientTests.cs (1)
  • IRestClientBuilder (33-42)
Activout.RestClient.Newtonsoft.Json.Test/SerializationOrderTest.cs (1)
  • IRestClientBuilder (77-83)
Activout.RestClient/Implementation/RestClientBuilder.cs (13)
Activout.RestClient/Implementation/RestClient.cs (2)
  • RestClient (10-47)
  • RestClient (18-22)
Activout.RestClient/IRestClientBuilder.cs (14)
  • IRestClientBuilder (13-13)
  • IRestClientBuilder (14-14)
  • IRestClientBuilder (15-15)
  • IRestClientBuilder (16-16)
  • IRestClientBuilder (17-17)
  • IRestClientBuilder (18-18)
  • IRestClientBuilder (19-19)
  • IRestClientBuilder (20-20)
  • IRestClientBuilder (21-21)
  • IRestClientBuilder (22-22)
  • IRestClientBuilder (23-23)
  • IRestClientBuilder (24-24)
  • IRestClientBuilder (25-25)
  • T (26-26)
Activout.RestClient/MediaType.cs (2)
  • MediaType (8-11)
  • MediaType (15-22)
Activout.RestClient/Helpers/Implementation/DuckTyping.cs (1)
  • DuckTyping (5-13)
Activout.RestClient/DomainExceptions/DefaultDomainExceptionMapperFactory.cs (2)
  • List (30-43)
  • DefaultDomainExceptionMapperFactory (9-90)
Activout.RestClient/Serialization/Implementation/SerializationManager.cs (4)
  • ISerializer (43-47)
  • IDeserializer (37-41)
  • SerializationManager (8-48)
  • SerializationManager (30-35)
Activout.RestClient/Implementation/HeaderListExtensions.cs (1)
  • AddOrReplaceHeader (8-18)
Activout.RestClient/Helpers/Implementation/TaskConverter3Factory.cs (1)
  • TaskConverter3Factory (5-15)
Activout.RestClient/ParamConverter/Implementation/ParamConverterManager.cs (2)
  • ParamConverterManager (7-31)
  • ParamConverterManager (13-17)
Activout.RestClient/Implementation/DummyRequestLogger.cs (2)
  • DummyRequestLogger (6-19)
  • DummyRequestLogger (10-12)
Activout.RestClient/ContentTypeAttribute.cs (1)
  • ContentTypeAttribute (10-13)
Activout.RestClient/DomainExceptions/DomainExceptionAttribute.cs (1)
  • DomainExceptionAttribute (10-18)
Activout.RestClient/HeaderAttribute.cs (1)
  • HeaderAttribute (12-17)
Activout.RestClient/Serialization/IDeserializer.cs (5)
Activout.RestClient/Serialization/Implementation/SerializationManager.cs (1)
  • IDeserializer (37-41)
Activout.RestClient/Serialization/ISerializationManager.cs (1)
  • IDeserializer (6-6)
Activout.RestClient/Serialization/Implementation/StringDeserializer.cs (1)
  • CanDeserialize (19-22)
Activout.RestClient/Serialization/Implementation/ByteArrayDeserializer.cs (1)
  • CanDeserialize (36-39)
Activout.RestClient/MediaType.cs (2)
  • MediaType (8-11)
  • MediaType (15-22)
Activout.RestClient/Serialization/Implementation/SerializationManager.cs (1)
Activout.RestClient/Serialization/Implementation/StringSerializer.cs (1)
  • StringSerializer (7-18)
Activout.RestClient/Serialization/Implementation/StringDeserializer.cs (4)
Activout.RestClient/Serialization/Implementation/SerializationManager.cs (1)
  • IDeserializer (37-41)
Activout.RestClient/Serialization/IDeserializer.cs (2)
  • Task (10-10)
  • CanDeserialize (11-11)
Activout.RestClient/Implementation/RequestHandler.cs (7)
  • Task (452-509)
  • Task (511-546)
  • Task (548-559)
  • Task (561-574)
  • HttpContent (427-434)
  • HttpContent (436-449)
  • Type (151-158)
Activout.RestClient/MediaType.cs (2)
  • MediaType (8-11)
  • MediaType (15-22)
Activout.RestClient/IRestClientBuilder.cs (2)
Activout.RestClient/Implementation/RestClientBuilder.cs (15)
  • IRestClientBuilder (45-49)
  • IRestClientBuilder (51-55)
  • IRestClientBuilder (57-61)
  • IRestClientBuilder (63-67)
  • IRestClientBuilder (69-73)
  • IRestClientBuilder (75-79)
  • IRestClientBuilder (81-85)
  • IRestClientBuilder (87-96)
  • IRestClientBuilder (98-107)
  • IRestClientBuilder (109-119)
  • IRestClientBuilder (121-125)
  • IRestClientBuilder (127-131)
  • IRestClientBuilder (133-137)
  • Uri (200-210)
  • T (139-170)
Activout.RestClient/RestClientBuilderExtensions.cs (2)
  • IRestClientBuilder (8-11)
  • IRestClientBuilder (13-16)
Activout.RestClient/RestClientBuilderExtensions.cs (3)
Activout.RestClient/IRestClientBuilder.cs (13)
  • IRestClientBuilder (13-13)
  • IRestClientBuilder (14-14)
  • IRestClientBuilder (15-15)
  • IRestClientBuilder (16-16)
  • IRestClientBuilder (17-17)
  • IRestClientBuilder (18-18)
  • IRestClientBuilder (19-19)
  • IRestClientBuilder (20-20)
  • IRestClientBuilder (21-21)
  • IRestClientBuilder (22-22)
  • IRestClientBuilder (23-23)
  • IRestClientBuilder (24-24)
  • IRestClientBuilder (25-25)
Activout.RestClient/Implementation/RestClientBuilder.cs (4)
  • IRestClientBuilder (45-49)
  • IRestClientBuilder (51-55)
  • IRestClientBuilder (57-61)
  • Uri (200-210)
Activout.RestClient/MediaType.cs (2)
  • MediaType (8-11)
  • MediaType (15-22)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (csharp)
🔇 Additional comments (13)
Activout.RestClient/Serialization/Implementation/StringDeserializer.cs (3)

5-6: LGTM: File-scoped namespace applied correctly.

The file-scoped namespace declaration aligns with the coding guidelines.


7-7: LGTM: Appropriate access modifier for implementation class.

Making the class internal is correct since it's an implementation detail, while the public interface IDeserializer remains accessible.


9-9: LGTM: Init-only Order property provides immutability.

The init accessor correctly satisfies the interface's get-only requirement while allowing initialization-time configuration and preventing post-construction mutation.

Activout.RestClient/Serialization/IDeserializer.cs (2)

5-6: LGTM: File-scoped namespace applied correctly.

The file-scoped namespace declaration aligns with the coding guidelines.


9-9: LGTM: Read-only Order property enforces immutability.

Changing the Order property to get-only aligns with the PR objective of making components more immutable. Implementations remain compatible using { get; set; } or { get; init; } accessors.

Activout.RestClient/Serialization/ISerializer.cs (2)

4-5: LGTM: File-scoped namespace applied correctly.

The file-scoped namespace declaration aligns with the coding guidelines and is consistent with the other interface changes in this PR.


8-8: LGTM: Read-only Order property enforces immutability.

Changing the Order property to get-only mirrors the IDeserializer change and aligns with the PR objective of making components more immutable. All observed implementations remain compatible with { get; set; } accessors.

Activout.RestClient.Newtonsoft.Json.Test/NewtonsoftJsonDeserializerTest.cs (3)

44-46: LGTM: test payloads clearly exercise Pascal vs camel case.

Anonymous objects match expected JSON property casing; assertions read clean.

Also applies to: 65-67


93-101: Good rename and use of shared CamelCase settings.

Using NewtonsoftJsonDefaults.CamelCaseSerializerSettings keeps tests aligned with library defaults.


110-116: Constructor overload improves test ergonomics.

Optional JsonSerializerSettings passthrough to WithNewtonsoftJson is tidy and explicit.

Activout.RestClient/Serialization/Implementation/SerializationManager.cs (1)

10-16: Switch to StringSerializer.Instance is correct.

Singleton avoids unnecessary allocations and matches new StringSerializer design.

Activout.RestClient/IRestClientBuilder.cs (2)

15-16: Header default replace=true aligns with HeaderAttribute.

Consistent semantics avoid duplicate headers when mixing attributes and builder calls.


25-26: Interface parity: ParamConverter manager exposed.

Keeps IRestClientBuilder aligned with implementation and extensions.

@twogood twogood merged commit 378da2d into main Oct 25, 2025
8 of 9 checks passed
@twogood twogood deleted the refactor-rest-context branch October 25, 2025 15:35
@coderabbitai coderabbitai bot mentioned this pull request Oct 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant