Skip to content

Commit 668dbfd

Browse files
committed
[csharp][restsharp] add throwOnAnyError option to surface client errors
By default, RestSharp swallows deserialization and transport exceptions into RestResponse.ErrorException, and the generated ToApiResponse<T> in this template only carries ErrorText — the actual exception is dropped. Combined with a generated GetXxxAsync that returns Data directly, callers silently receive null on any deserialization failure (e.g. a required property missing in the upstream JSON). The error never reaches application logs or APM. Add an opt-in `throwOnAnyError` switch (default false, restsharp library only) that sets `ThrowOnAnyError = true` on RestClientOptions, making RestSharp rethrow the original ApiException(500, ...) that the generated deserializer already throws. The exception then propagates to the caller and into normal application error handling. Default kept off to preserve backwards compatibility — opt in when you want bugs to surface instead of silently producing null/[].
1 parent 8a65919 commit 668dbfd

3 files changed

Lines changed: 14 additions & 1 deletion

File tree

docs/generators/csharp.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
5151
|useDateTimeForDate|Use DateTime to model date properties even if DateOnly supported. (.net 6.0+ only)| |false|
5252
|useDateTimeOffset|Use DateTimeOffset to model date-time properties| |false|
5353
|useIntForTimeout|Use int for Timeout (fall back to v7.9.0 templates). This option (for restsharp only) will be deprecated so please migrated to TimeSpan instead.| |false|
54+
|throwOnAnyError|Configure RestSharp to rethrow deserialization and transport errors instead of swallowing them into RestResponse.ErrorException (which the default ToApiResponse&lt;T&gt; discards as null Data). Recommended for production use to surface bugs that would otherwise be invisible. (restsharp only)| |false|
5455
|useOneOfDiscriminatorLookup|Use the discriminator's mapping in oneOf to speed up the model lookup. IMPORTANT: Validation (e.g. one and only one match in oneOf's schemas) will be skipped.| |false|
5556
|useSourceGeneration|Use source generation where available (only `generichost` library supports this option).| |false|
5657
|useVirtualForHooks|Generate code that exposes public virtual hooks on ApiClient to customize low-level HTTP requests (only `restsharp`. `httpclient` libraries support this option).| |false|

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CSharpClientCodegen.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ public class CSharpClientCodegen extends AbstractCSharpCodegen {
122122
protected boolean supportsFileParameters = Boolean.TRUE;
123123
protected boolean supportsDateOnly = Boolean.FALSE;
124124
protected boolean useIntForTimeout = Boolean.FALSE;
125+
protected boolean throwOnAnyError = Boolean.FALSE;
125126

126127
@Setter protected boolean validatable = Boolean.TRUE;
127128
@Setter protected boolean equatable = Boolean.FALSE;
@@ -132,6 +133,7 @@ public class CSharpClientCodegen extends AbstractCSharpCodegen {
132133
private static final String OPERATION_PARAMETER_SORTING_KEY = "operationParameterSorting";
133134
private static final String MODEL_PROPERTY_SORTING_KEY = "modelPropertySorting";
134135
private static final String USE_INT_FOR_TIMEOUT = "useIntForTimeout";
136+
private static final String THROW_ON_ANY_ERROR = "throwOnAnyError";
135137

136138
enum SortingMethod {
137139
DEFAULT,
@@ -249,6 +251,10 @@ public CSharpClientCodegen() {
249251
"Use int for Timeout (fall back to v7.9.0 templates). This option (for restsharp only) will be deprecated so please migrated to TimeSpan instead.",
250252
String.valueOf(this.useIntForTimeout));
251253

254+
addSwitch(CSharpClientCodegen.THROW_ON_ANY_ERROR,
255+
"Configure RestSharp to rethrow deserialization and transport errors instead of swallowing them into RestResponse.ErrorException (which the default ToApiResponse<T> discards as null Data). Recommended for production use to surface bugs that would otherwise be invisible. (restsharp only)",
256+
this.throwOnAnyError);
257+
252258
CliOption framework = new CliOption(
253259
CodegenConstants.DOTNET_FRAMEWORK,
254260
CodegenConstants.DOTNET_FRAMEWORK_DESC
@@ -871,6 +877,7 @@ public void processOpts() {
871877
syncBooleanProperty(additionalProperties, "useSourceGeneration", this::setUseSourceGeneration, this.useSourceGeneration);
872878
syncBooleanProperty(additionalProperties, "supportsDateOnly", this::setSupportsDateOnly, this.supportsDateOnly);
873879
syncBooleanProperty(additionalProperties, "useIntForTimeout", this::setUseIntForTimeout, this.useIntForTimeout);
880+
syncBooleanProperty(additionalProperties, "throwOnAnyError", this::setThrowOnAnyError, this.throwOnAnyError);
874881

875882
final String testPackageName = testPackageName();
876883
String packageFolder = sourceFolder + File.separator + packageName;
@@ -1244,6 +1251,10 @@ public void setUseIntForTimeout(Boolean useIntForTimeout) {
12441251
this.useIntForTimeout = useIntForTimeout;
12451252
}
12461253

1254+
public void setThrowOnAnyError(Boolean throwOnAnyError) {
1255+
this.throwOnAnyError = throwOnAnyError;
1256+
}
1257+
12471258
public void setSupportsRetry(Boolean supportsRetry) {
12481259
this.supportsRetry = supportsRetry;
12491260
}

modules/openapi-generator/src/main/resources/csharp/ApiClient.mustache

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,8 @@ namespace {{packageName}}.Client
467467
Proxy = configuration.Proxy,
468468
UserAgent = configuration.UserAgent,
469469
UseDefaultCredentials = configuration.UseDefaultCredentials,
470-
RemoteCertificateValidationCallback = configuration.RemoteCertificateValidationCallback
470+
RemoteCertificateValidationCallback = configuration.RemoteCertificateValidationCallback{{#throwOnAnyError}},
471+
ThrowOnAnyError = true{{/throwOnAnyError}}
471472
};
472473
setOptions(clientOptions);
473474

0 commit comments

Comments
 (0)