Nswag: InvalidCastException in WebApiToSwaggerGenerator.GetSupportedHttpMethodsFromAttributes

Created on 3 Apr 2018  路  14Comments  路  Source: RicoSuter/NSwag

Using nswag run nswag.json /runtime:NetCore20, I get an InvalidCastException thrown from the WebApiToSwaggerGenerator class:

System.InvalidCastException: Unable to cast object of type 
'SelectArrayIterator`2[System.String,System.String]' to type
'System.Collections.ICollection'.
   at CallSite.Target(Closure , CallSite , Object )
   at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
   at NSwag.SwaggerGeneration.WebApi.WebApiToSwaggerGenerator.<GetSupportedHttpMethodsFromAttributes>d__24.MoveNext() in C:\projects\nswag\src\NSwag.SwaggerGeneration.WebApi\WebApiToSwaggerGenerator.cs:line 482
   at System.Collections.Generic.LargeArrayBuilder`1.AddRange(IEnumerable`1 items)
   at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source)
   at NSwag.SwaggerGeneration.WebApi.WebApiToSwaggerGenerator.<GetSupportedHttpMethods>d__23.MoveNext() in C:\projects\nswag\src\NSwag.SwaggerGeneration.WebApi\WebApiToSwaggerGenerator.cs:line 429
   at System.Collections.Generic.List`1.AddEnumerable(IEnumerable`1 enumerable)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at NSwag.SwaggerGeneration.WebApi.WebApiToSwaggerGenerator.<GenerateForControllerAsync>d__11.MoveNext() in C:\projects\nswag\src\NSwag.SwaggerGeneration.WebApi\WebApiToSwaggerGenerator.cs:line 143
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NSwag.SwaggerGeneration.WebApi.WebApiToSwaggerGenerator.<GenerateForControllersAsync>d__9.MoveNext() in C:\projects\nswag\src\NSwag.SwaggerGeneration.WebApi\WebApiToSwaggerGenerator.cs:line 95
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NSwag.Commands.SwaggerGeneration.WebApiToSwaggerCommand.<RunIsolatedAsync>d__91.MoveNext() in C:\projects\nswag\src\NSwag.Commands\Commands\SwaggerGeneration\WebApiToSwaggerCommand.cs:line 198
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   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 60
   at NSwag.Commands.IsolatedCommandBase`1.<>c__DisplayClass13_0.<RunIsolatedAsync>b__0() in C:\projects\nswag\src\NSwag.Commands\Commands\IsolatedCommandBase.cs:line 50
   at System.Threading.Tasks.Task`1.InnerInvoke()
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NSwag.Commands.IsolatedCommandBase`1.<RunIsolatedAsync>d__13.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NSwag.Commands.IsolatedSwaggerOutputCommandBase.<RunAsync>d__4.MoveNext() in C:\projects\nswag\src\NSwag.Commands\Commands\IsolatedSwaggerOutputCommandBase.cs:line 24
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NSwag.Commands.NSwagDocumentBase.<GenerateSwaggerDocumentAsync>d__40.MoveNext() in C:\projects\nswag\src\NSwag.Commands\NSwagDocumentBase.cs:line 268
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NSwag.Commands.NSwagDocument.<ExecuteAsync>d__4.MoveNext() in C:\projects\nswag\src\NSwag.Commands\NSwagDocument.cs:line 76
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NSwag.Commands.Document.ExecuteDocumentCommand.<ExecuteDocumentAsync>d__9.MoveNext() in C:\projects\nswag\src\NSwag.Commands\Commands\Document\ExecuteDocumentCommand.cs:line 77
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NSwag.Commands.Document.ExecuteDocumentCommand.<RunAsync>d__8.MoveNext() in C:\projects\nswag\src\NSwag.Commands\Commands\Document\ExecuteDocumentCommand.cs:line 31
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NConsole.CommandLineProcessor.<ProcessSingleAsync>d__12.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NConsole.CommandLineProcessor.<ProcessAsync>d__11.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   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 54

Looking at the code on master, I think the problem might be here, where the code tries to cast a property of the dynamic object to ICollection:

dynamic acceptVerbsAttribute = method.GetCustomAttributes()
    .SingleOrDefault(a => a.GetType().Name == "AcceptVerbsAttribute");

if (acceptVerbsAttribute != null)
{
    foreach (var verb in ((ICollection)acceptVerbsAttribute.HttpMethods).OfType<object>().Select(v => v.ToString().ToLowerInvariant()))

The AcceptVerbsAttribute.HttpMethods property is of type IEnumerable<string>, so the cast to ICollection is optimistic in this case. Considering the method only enumerates the result, a fix may be to change the cast to IEnumerable instead.

Most helpful comment

Both problems seem resolved by this build.

All 14 comments

The problem is that this was implemented for the old attribute which was actually a collection of enums:

https://msdn.microsoft.com/en-us/library/system.web.http.acceptverbsattribute.httpmethods(v=vs.118).aspx#P:System.Web.Http.AcceptVerbsAttribute.HttpMethods

We need to support both...

Is this problem being managed in another issue? Is there anything I can contribute to help?

Already fixed :)

Please test with the CI artifacts as soon as it's done: https://ci.appveyor.com/project/rsuter/nswag-25x6o/build/artifacts

I am having trouble testing: I think there's a problem reading my nswag.json file. Would you like me to create an issue for it?

What's the problem?

JsonReaderException: After parsing a value an unexpected character was encountered: D. Path 'swaggerGenerator.webApiToSwagger.assemblyPaths[0]', line 26, position 109.

My assemblyPaths looks like:

25    "assemblyPaths": [
26        "bin/$(Configuration)/netcoreapp2.0/MyApi.dll"
27    ],

I have Confguration defined under defaultVariables:

"defaultVariables": "Configuration=Debug",

From the call stack, I can see this originates in NSwag.Commands.NSwagDocumentBase.FromJson[TDocument](String filePath, String data)

   at Newtonsoft.Json.JsonTextReader.ParsePostValue()
   at Newtonsoft.Json.JsonTextReader.Read()
   at Newtonsoft.Json.JsonWriter.WriteToken(JsonReader reader, Boolean writeChildren, Boolean writeDateConstructorAsDate, Boolean writeComments)
   at Newtonsoft.Json.JsonWriter.WriteToken(JsonReader reader, Boolean writeChildren)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateJToken(JsonReader reader, JsonContract contract)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at NSwag.Commands.NSwagDocumentBase.FromJson[TDocument](String filePath, String data) in C:\projects\nswag-25x6o\src\NSwag.Commands\NSwagDocumentBase.cs:line 218
   at NSwag.Commands.NSwagDocumentBase.<>c__DisplayClass35_0`1.<<LoadAsync>b__0>d.MoveNext() in C:\projects\nswag-25x6o\src\NSwag.Commands\NSwagDocumentBase.cs:line 200
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NSwag.Commands.NSwagDocument.<LoadWithTransformationsAsync>d__3.MoveNext() in C:\projects\nswag-25x6o\src\NSwag.Commands\NSwagDocument.cs:line 65
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NSwag.Commands.SwaggerGeneration.ListWebApiControllersCommand.<RunAsync>d__8.MoveNext() in C:\projects\nswag-25x6o\src\NSwag.Commands\Commands\SwaggerGeneration\ListWebApiControllersCommand.cs:line 33
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NConsole.CommandLineProcessor.<ProcessSingleAsync>d__12.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NConsole.CommandLineProcessor.<ProcessAsync>d__11.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NConsole.CommandLineProcessor.Process(String[] args, Object input)
   at NSwag.Commands.NSwagCommandProcessor.Process(String[] args) in C:\projects\nswag-25x6o\src\NSwag.Commands\NSwagCommandProcessor.cs:line 54

Yes, its a regression from this PR: https://github.com/RSuter/NSwag/pull/1252

Will continue/re-test when linked to new artefacts.

Sorry, already fixed :-)

Seems you have been faster, but did the same Thing + a null check, which I did not..

Both problems seem resolved by this build.

Was this page helpful?
0 / 5 - 0 ratings