diff --git a/modules/openapi-generator/src/main/resources/csharp/ApiClient.mustache b/modules/openapi-generator/src/main/resources/csharp/ApiClient.mustache index bad3fbfa9cb2..996c435c84ac 100644 --- a/modules/openapi-generator/src/main/resources/csharp/ApiClient.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/ApiClient.mustache @@ -511,7 +511,17 @@ namespace {{packageName}}.Client } catch (Exception ex) { + {{#throwOnAnyError}} + // 4xx/5xx are left to ExceptionFactory, like the ErrorException check above + if ((int)response.StatusCode < 400) + { + var error = ex.InnerException != null ? ex.InnerException : ex; + throw new ApiException((int)response.StatusCode, string.Format("Error calling {0}: {1}", request.Resource, error.Message), response.Content, ToApiResponse(response).Headers, error); + } + {{/throwOnAnyError}} + {{^throwOnAnyError}} throw ex.InnerException != null ? ex.InnerException : ex; + {{/throwOnAnyError}} } } else if (typeof(T).Name == "Stream") // for binary response diff --git a/modules/openapi-generator/src/main/resources/csharp/ApiClient.v790.mustache b/modules/openapi-generator/src/main/resources/csharp/ApiClient.v790.mustache index d2f74ed945d4..bc111a73c080 100644 --- a/modules/openapi-generator/src/main/resources/csharp/ApiClient.v790.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/ApiClient.v790.mustache @@ -503,7 +503,17 @@ namespace {{packageName}}.Client } catch (Exception ex) { + {{#throwOnAnyError}} + // 4xx/5xx are left to ExceptionFactory, like the ErrorException check above + if ((int)response.StatusCode < 400) + { + var error = ex.InnerException != null ? ex.InnerException : ex; + throw new ApiException((int)response.StatusCode, string.Format("Error calling {0}: {1}", request.Resource, error.Message), response.Content, ToApiResponse(response).Headers, error); + } + {{/throwOnAnyError}} + {{^throwOnAnyError}} throw ex.InnerException != null ? ex.InnerException : ex; + {{/throwOnAnyError}} } } else if (typeof(T).Name == "Stream") // for binary response diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/csharpnetcore/CSharpClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/csharpnetcore/CSharpClientCodegenTest.java index f4d3bb56ba5d..61087564e760 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/csharpnetcore/CSharpClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/csharpnetcore/CSharpClientCodegenTest.java @@ -448,6 +448,46 @@ public void testUserAgentIsNotUrlEncoded() throws IOException { } } + @Test + public void testThrowOnAnyErrorWrapsOneOfDeserializationFailure() throws IOException { + // both restsharp ApiClient templates: the default one and the useIntForTimeout v7.9.0 fallback + for (boolean useIntForTimeout : new boolean[]{false, true}) { + for (boolean throwOnAnyError : new boolean[]{false, true}) { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/petstore.yaml"); + final DefaultGenerator defaultGenerator = new DefaultGenerator(); + final ClientOptInput clientOptInput = new ClientOptInput(); + clientOptInput.openAPI(openAPI); + CSharpClientCodegen cSharpClientCodegen = new CSharpClientCodegen(); + cSharpClientCodegen.setLibrary("restsharp"); + cSharpClientCodegen.setOutputDir(output.getAbsolutePath()); + cSharpClientCodegen.additionalProperties().put("useIntForTimeout", useIntForTimeout); + cSharpClientCodegen.additionalProperties().put("throwOnAnyError", throwOnAnyError); + clientOptInput.config(cSharpClientCodegen); + defaultGenerator.opts(clientOptInput); + + Map files = defaultGenerator.generate().stream() + .collect(Collectors.toMap(File::getPath, Function.identity())); + + File apiClient = files + .get(Paths.get(output.getAbsolutePath(), "src", "Org.OpenAPITools", "Client", "ApiClient.cs").toString()); + assertNotNull(apiClient); + String wrapped = "throw new ApiException((int)response.StatusCode, string.Format(\"Error calling {0}: {1}\", request.Resource, error.Message), response.Content, ToApiResponse(response).Headers, error);"; + // 4xx/5xx must still reach ExceptionFactory, so only lower status codes are wrapped here + String wrappedBelow400 = "if ((int)response.StatusCode < 400) { var error = ex.InnerException != null ? ex.InnerException : ex; " + wrapped + " }"; + String rethrown = "throw ex.InnerException != null ? ex.InnerException : ex;"; + if (throwOnAnyError) { + assertFileContains(apiClient.toPath(), wrappedBelow400); + assertFileNotContains(apiClient.toPath(), rethrown); + } else { + assertFileContains(apiClient.toPath(), rethrown); + assertFileNotContains(apiClient.toPath(), wrapped); + } + } + } + } + @Test public void testSelectHeaderAcceptKeepsAllTypesJsonFirst() throws IOException { File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); diff --git a/samples/client/petstore/csharp/restsharp/net4.7/MultipleFrameworks/src/Org.OpenAPITools/Client/ApiClient.cs b/samples/client/petstore/csharp/restsharp/net4.7/MultipleFrameworks/src/Org.OpenAPITools/Client/ApiClient.cs index 58091fdfa71e..5d4eab7fb08f 100644 --- a/samples/client/petstore/csharp/restsharp/net4.7/MultipleFrameworks/src/Org.OpenAPITools/Client/ApiClient.cs +++ b/samples/client/petstore/csharp/restsharp/net4.7/MultipleFrameworks/src/Org.OpenAPITools/Client/ApiClient.cs @@ -508,7 +508,12 @@ private async Task> ExecClientAsync(Func