RicoSuter / NSwag

The Swagger/OpenAPI toolchain for .NET, ASP.NET Core and TypeScript.
http://NSwag.org
MIT License
6.67k stars 1.23k forks source link

Duplicate return code declaration causes nasty exception #2863

Open alalloo opened 4 years ago

alalloo commented 4 years ago

A controller might have several reasons to return a bad request status and in our project had them declared like below which is handled OK by Swagger. But switching to NSwag was problematic since it caused an exception and it was really hard knowing what NSwag was unhappy about. I had to clone nswag repo and debug it to find what was the problem (which then could trivially be corrected).

A proper error message to user would have saved a couple of hours.

    /// <returns>Updated insured object.</returns>
    /// <response code="400">Bad request, missing information or similar.</response>
    /// <response code="400">Unknown category.</response>
    /// <response code="409">Attempt to update read-only properties.</response>

The exception

System.InvalidOperationException: Sequence contains more than one matching element

Runtime: NetCore31
   at System.Linq.ThrowHelper.ThrowMoreThanOneMatchException()
   at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
   at NSwag.Generation.Processors.OperationResponseProcessorBase.GetResponseXmlDocsElement(MethodInfo methodInfo, String responseCode) in C:\projects\nswag\src\NSwag.Generation\Processors\OperationResponseProcessorBase.cs:line 92
   at NSwag.Generation.Processors.OperationResponseProcessorBase.UpdateResponseDescription(OperationProcessorContext operationProcessorContext) in C:\projects\nswag\src\NSwag.Generation\Processors\OperationResponseProcessorBase.cs:line 59
   at NSwag.Generation.WebApi.Processors.OperationResponseProcessor.Process(OperationProcessorContext context) in C:\projects\nswag\src\NSwag.Generation.WebApi\Processors\OperationResponseProcessor.cs:line 52
   at NSwag.Generation.WebApi.WebApiOpenApiDocumentGenerator.RunOperationProcessors(OpenApiDocument document, Type controllerType, MethodInfo methodInfo, OpenApiOperationDescription operationDescription, List`1 allOperations, OpenApiDocumentGenerator swaggerGenerator, OpenApiSchemaResolver schemaResolver) in C:\projects\nswag\src\NSwag.Generation.WebApi\WebApiOpenApiDocumentGenerator.cs:line 241
   at NSwag.Generation.WebApi.WebApiOpenApiDocumentGenerator.AddOperationDescriptionsToDocument(OpenApiDocument document, Type controllerType, List`1 operations, OpenApiDocumentGenerator swaggerGenerator, OpenApiSchemaResolver schemaResolver) in C:\projects\nswag\src\NSwag.Generation.WebApi\WebApiOpenApiDocumentGenerator.cs:line 211
   at NSwag.Generation.WebApi.WebApiOpenApiDocumentGenerator.GenerateForController(OpenApiDocument document, Type controllerType, OpenApiDocumentGenerator swaggerGenerator, OpenApiSchemaResolver schemaResolver) in C:\projects\nswag\src\NSwag.Generation.WebApi\WebApiOpenApiDocumentGenerator.cs:line 199
   at NSwag.Generation.WebApi.WebApiOpenApiDocumentGenerator.GenerateForControllersAsync(IEnumerable`1 controllerTypes) in C:\projects\nswag\src\NSwag.Generation.WebApi\WebApiOpenApiDocumentGenerator.cs:line 88
   at NSwag.Commands.Generation.WebApi.WebApiToSwaggerCommand.RunIsolatedAsync(AssemblyLoader assemblyLoader) in C:\projects\nswag\src\NSwag.Commands\Commands\Generation\WebApi\WebApiToOpenApiCommand.cs:line 109
   at NSwag.Commands.IsolatedCommandBase`1.IsolatedCommandAssemblyLoader`1.Run(String commandType, String commandData, String[] assemblyPaths, String[] referencePaths) in C:\projects\nswag\src\NSwag.Commands\Commands\IsolatedCommandBase.cs:line 76
   at NSwag.Commands.IsolatedCommandBase`1.<>c__DisplayClass17_0.<RunIsolatedAsync>b__0() in C:\projects\nswag\src\NSwag.Commands\Commands\IsolatedCommandBase.cs:line 61
   at System.Threading.Tasks.Task`1.InnerInvoke()
   at System.Threading.Tasks.Task.<>c.<.cctor>b__274_0(Object obj)
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location where exception was thrown ---
   at NSwag.Commands.IsolatedCommandBase`1.RunIsolatedAsync(String configurationFile) in C:\projects\nswag\src\NSwag.Commands\Commands\IsolatedCommandBase.cs:line 61
   at NSwag.Commands.IsolatedSwaggerOutputCommandBase`1.RunAsync(CommandLineProcessor processor, IConsoleHost host) in C:\projects\nswag\src\NSwag.Commands\Commands\IsolatedSwaggerOutputCommandBase.cs:line 47
   at NSwag.Commands.NSwagDocumentBase.GenerateSwaggerDocumentAsync() in C:\projects\nswag\src\NSwag.Commands\NSwagDocumentBase.cs:line 280
   at NSwag.Commands.NSwagDocument.ExecuteAsync() in C:\projects\nswag\src\NSwag.Commands\NSwagDocument.cs:line 81
   at NSwag.Commands.Document.ExecuteDocumentCommand.ExecuteDocumentAsync(IConsoleHost host, String filePath) in C:\projects\nswag\src\NSwag.Commands\Commands\Document\ExecuteDocumentCommand.cs:line 86
   at NSwag.Commands.Document.ExecuteDocumentCommand.RunAsync(CommandLineProcessor processor, IConsoleHost host) in C:\projects\nswag\src\NSwag.Commands\Commands\Document\ExecuteDocumentCommand.cs:line 32
   at NConsole.CommandLineProcessor.ProcessSingleAsync(String[] args, Object input)
   at NConsole.CommandLineProcessor.ProcessAsync(String[] args, Object input)
   at NConsole.CommandLineProcessor.Process(String[] args, Object input)
   at NSwag.Commands.NSwagCommandProcessor.Process(String[] args) in C:\projects\nswag\src\NSwag.Commands\NSwagCommandProcessor.cs:line 56
RicoSuter commented 3 years ago

I'd say you should have only one of them and merge the descriptions.

alalloo commented 3 years ago

Absolutely, and that was the fix I did - this issue is only a suggestion to make the cause of the problem be understandable from the returned error message since it took me a really long time to figure out what the problem was, from diving into nswag source code.

aviita commented 1 year ago

Would also appreciate better error message. Took me also some time before I noticed to read the call stack far enough to notice this was about XML docs. Was searching for actual code changes that could have some duplication like Attributes. Anyways the information was hiding in plain sight in that call stack. Also did not find this issue with google using the error message.

Executing file 'nswag.json' with variables ''... System.InvalidOperationException: Sequence contains more than one matching element at System.Linq.ThrowHelper.ThrowMoreThanOneMatchException() at System.Linq.Enumerable.TryGetSingle[TSource](IEnumerable1 source, Func2 predicate, Boolean& found) at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable1 source, Func2 predicate) at NSwag.Generation.Processors.OperationResponseProcessorBase.GetResponseXmlDocsElement(MethodInfo methodInfo, String responseCode) in /_/src/NSwag.Generation/Processors/OperationResponseProcessorBase.cs:line 97

aviita commented 1 year ago

Created a PR #4388. Did not test it yet though as I could not get the nswag repo's build to work.

BenJenkinson commented 1 year ago

I've also run into this problem today.

I agree that a more descriptive error message/console output from NSwag would be really useful in tracking down which endpoint it was choking on.

aviita commented 2 months ago

Since the PR #4388 has been merged, could this issue be closed?