[csharp][restsharp] throwOnAnyError: throw ApiException instead of raw RestSharp exceptions
throwOnAnyError (#23663) sets RestSharp's ThrowOnAnyError, which also throws HttpRequestException for every 4xx/5xx before ExceptionFactory runs, breaking the ApiException contract; transport failures surface as raw HttpRequestException.
Option stays opt-in but is implemented in ApiClient: if RestSharp recorded an ErrorException and status < 400, throw ApiException with the status (0 transport, real 2xx for deserialization failures), body and headers; 4xx/5xx still go through ExceptionFactory; retry-policy failures return the error response so the same guard covers them.
Also adds ApiException(int, string, object, Multimap<string, string>, Exception innerException) so the original RestSharp exception is kept as InnerException (stack trace preserved; the retry-policy path previously had no message at all). The constructor lives in the shared ApiException.mustache, so httpclient and unityWebRequest clients gain it too — additive, existing constructors unchanged.
Behaviour change for users who already opted into throwOnAnyError: RestSharp HttpRequestException becomes ApiException and 4xx/5xx go through ExceptionFactory.
Verified against the regenerated net4.7/MultipleFrameworks sample (refused → ApiException(0), 500 → ApiException(500) with body/headers, malformed 200 → ApiException(200)); on master the first two were HttpRequestException. Related: #15471, #8732, #10903, #15379, #15241.
cc @mandrean @shibayan @Blackclaws @lucamazzanti
PR checklist
- Read the contribution guidelines.
- Run the following to build the project and update samples:
(For Windows users, please run the script in WSL)./mvnw clean package || exit ./bin/generate-samples.sh ./bin/configs/*.yaml || exit ./bin/utils/export_docs_generators.sh || exit
Commit all changed files.
This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
These must match the expectations made by your contribution.
You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example./bin/generate-samples.sh bin/configs/java*.
IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed. - If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.
Summary by cubic
Fixes throwOnAnyError so transport and deserialization failures surface as ApiException instead of raw RestSharp HttpRequestException.
Previously the option enabled RestSharp's ThrowOnAnyError, which threw HttpRequestException for every non-2xx response before ExceptionFactory could run. Now 4xx/5xx responses keep flowing through ExceptionFactory, and only errors with status below 400 throw ApiException with the status (0 for transport failures, the real 2xx for deserialization failures), response body, and headers. The retry-policy path returns the error response so the same guard covers it.
ApiExceptionnow accepts an inner exception so the original stack trace and message survive the wrap. The constructor lives in the sharedApiException.mustache, so the httpclient and unityWebRequest clients gain it too, additively.- Adds tests to the
MultipleFrameworkssample covering transport failure and an unparseable 2xx body, both assertingApiExceptionwith the right status, body, and inner exception. - Behavior change: users who already opted in now get
ApiExceptionfor transport and deserialization failures, while ordinary HTTP error responses are handled byExceptionFactoryas usual.