Skip to content

Fix sync method pipeline to match async behavior (ExceptionFactory, IApiResponse, disposal)#2070

Merged
ChrisPulman merged 3 commits intoFixFor2065_2067from
copilot/sub-pr-2068-again
Mar 25, 2026
Merged

Fix sync method pipeline to match async behavior (ExceptionFactory, IApiResponse, disposal)#2070
ChrisPulman merged 3 commits intoFixFor2065_2067from
copilot/sub-pr-2068-again

Conversation

Copy link
Copy Markdown

Copilot AI commented Mar 25, 2026

The sync path for explicit/non-public interface members bypassed ExceptionFactory, ignored IsApiResponse, always disposed the response, and couldn't correctly return HttpResponseMessage/HttpContent/Stream/IApiResponse<T>.

Changes

Refit/RequestBuilderImplementation.cs

  • Replaced simplistic BuildGeneratedSyncFuncForMethod with a dispatcher: void returns run ExceptionFactory then return null; non-void delegates to new BuildGeneratedSyncFuncForMethodGeneric<T, TBody> via reflection.
  • BuildGeneratedSyncFuncForMethodGeneric<T, TBody> mirrors BuildCancellableTaskFuncForMethod exactly: skips ExceptionFactory for HttpResponseMessage, wraps in ApiResponse<TBody> when IsApiResponse, uses ShouldDisposeResponse for conditional cleanup, surfaces DeserializationExceptionFactory on deserialization failure.
  • Added DeserializeContentSync<T> handling HttpResponseMessage, HttpContent, Stream, string, and generic T (via content serializer).
  • Removed the now-obsolete DeserializeSyncResponse / DeserializeSyncResponseGeneric<T>.

Refit/RestMethodInfo.cs

  • Sync branch of DetermineReturnTypeInfo now decomposes IApiResponse<T>/ApiResponse<T> to set DeserializedResultType to the inner type, matching the Task<IApiResponse<T>> path.

Source generator (InterfaceStubGenerator.Shared)

  • Added ReturnTypeInfo.SyncVoid enum value; parser maps Void metadata name to it; emitter emits a plain call ______func(...) instead of the invalid return (void)______func(...).

Example

public interface IMyApi
{
    // These now behave identically to their Task<T> counterparts:
    [Get("/resource")]
    internal IApiResponse<MyDto> GetWithApiResponse();  // wraps error, no throw

    [Get("/resource")]
    internal HttpResponseMessage GetRaw();  // caller owns lifetime, no ExceptionFactory

    [Get("/resource")]
    internal void Delete();  // throws ApiException on non-success
}

⌨️ Start Copilot coding agent tasks without leaving your editor — available in VS Code, Visual Studio, JetBrains IDEs and Eclipse.

Copilot AI and others added 2 commits March 25, 2026 16:29
… behavior

- Rewrite BuildGeneratedSyncFuncForMethod as a dispatcher that handles
  void return separately and delegates non-void to a new generic method.
- Add BuildGeneratedSyncFuncForMethodGeneric<T,TBody> that mirrors the
  full async pipeline: runs ExceptionFactory (skipped for HttpResponseMessage),
  honours IsApiResponse, uses ShouldDisposeResponse for cleanup, and
  surfaces DeserializationExceptionFactory on deserialization errors.
- Add DeserializeContentSync<T> handling all content types:
  HttpResponseMessage, HttpContent, Stream, string, and deserialised T.
- Fix RestMethodInfo sync branch to properly decompose IApiResponse<T> /
  ApiResponse<T> return types, setting DeserializedResultType to the
  inner type just like the async Task<IApiResponse<T>> path does.
- Add SyncVoid to ReturnTypeInfo enum and handle it in Parser.cs and
  Emitter.cs so void-returning sync stub methods emit a plain call
  instead of the invalid 'return (void)...' pattern.
- Add comprehensive tests covering error responses, HttpResponseMessage,
  HttpContent, Stream, IApiResponse<T>, and void sync methods.

Co-authored-by: ChrisPulman <4910015+ChrisPulman@users.noreply.github.com>
Agent-Logs-Url: https://github.com/reactiveui/refit/sessions/7e184030-9d18-44ec-aff4-305b2c7e973d
Copy link
Copy Markdown
Author

Copilot AI commented Mar 25, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • 0t3vsblobprodcus362.vsblob.vsassets.io
    • Triggering command: /usr/bin/dotnet dotnet restore --no-dependencies /home/REDACTED/work/refit/refit/Refit.sln --packages /tmp/codeql-scratch-26cf538f58283729/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-26cf538f58283729/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-26cf538f58283729/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true (dns block)
    • Triggering command: /usr/bin/dotnet dotnet restore --no-dependencies /home/REDACTED/work/refit/refit/Refit.Benchmarks/Refit.Benchmarks.csproj --packages /tmp/codeql-scratch-26cf538f58283729/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-26cf538f58283729/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-26cf538f58283729/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true (dns block)
  • 1s1vsblobprodcus386.vsblob.vsassets.io
    • Triggering command: /usr/bin/dotnet dotnet restore --no-dependencies /home/REDACTED/work/refit/refit/Refit.sln --packages /tmp/codeql-scratch-26cf538f58283729/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-26cf538f58283729/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-26cf538f58283729/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true (dns block)
    • Triggering command: /usr/bin/dotnet dotnet restore --no-dependencies /home/REDACTED/work/refit/refit/Refit.Benchmarks/Refit.Benchmarks.csproj --packages /tmp/codeql-scratch-26cf538f58283729/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-26cf538f58283729/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-26cf538f58283729/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true (dns block)
  • https://api.github.com/%7B/path%7D
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/refit/refit/Refit.Tests/bin/Debug/net8.0/Refit.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/refit/refit/Refit.Tests/bin/Debug/net8.0/Refit.Tests.deps.json /home/REDACTED/work/refit/refit/Refit.Tests/bin/Debug/net8.0/testhost.dll --port 36003 --endpoint 127.0.0.1:036003 --role client --parentprocessid 6209 --telemetryoptedin false (http block)
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/refit/refit/Refit.Tests/bin/Debug/net8.0/Refit.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/refit/refit/Refit.Tests/bin/Debug/net8.0/Refit.Tests.deps.json /home/REDACTED/work/refit/refit/Refit.Tests/bin/Debug/net8.0/testhost.dll --port 38571 --endpoint 127.0.0.1:038571 --role client --parentprocessid 7219 --telemetryoptedin false (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI changed the title [WIP] [WIP] Address feedback on sync interface members & enum names implementation Fix sync method pipeline to match async behavior (ExceptionFactory, IApiResponse, disposal) Mar 25, 2026
Copilot AI requested a review from ChrisPulman March 25, 2026 16:36
@ChrisPulman ChrisPulman marked this pull request as ready for review March 25, 2026 17:05
@ChrisPulman ChrisPulman merged commit 2df9244 into FixFor2065_2067 Mar 25, 2026
@ChrisPulman ChrisPulman deleted the copilot/sub-pr-2068-again branch March 25, 2026 17:05
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.

2 participants