yahehe / Nancy.Swagger

Nancy plugin for generated API documentation in Swagger format.
MIT License
133 stars 60 forks source link

Fixes ArgumentException: An item with the same key has already been a… #119

Closed vvreutskiy closed 7 years ago

vvreutskiy commented 7 years ago

…dded

jnallard commented 7 years ago

You shouldn't have multiple definitions with the same name. I'd like to know what's causing that in your code.

From looking at this: https://github.com/vvreutskiy/Nancy.Swagger/blob/298220402c9490ca06596d4ee33d6f7ed7deddf2/src/Nancy.Swagger/Services/SwaggerMetadataProvider.cs#L75 It means you have multiple models with the same name, which should be avoided. When it does happen, you don't want to just ignore it - you want the exception so you can find the error and rename one of the models. There's possibly a deeper bug here that we want to find.

Can you show me what your related code looks like?

vvreutskiy commented 7 years ago

Here is the minimal code which reproduces error when loading /api-docs :

public class HelloModule : Nancy.NancyModule
{
    public HelloModule() : base("api")
    {
        var response1 = new ResponseWrapper<FirstResponse>
        {
            Response = new FirstResponse { Int = 1 }
        };

        Get("/op1", x => Response.AsJson(response1), null, "op1");

        var response2 = new ResponseWrapper<SecondResponse>
        {
            Response = new SecondResponse { Str = "two" }
        };

        Get("/op2", x => Response.AsJson(response2), null, "op2");
    }
}

public class HelloMetadataModule : SwaggerMetadataModule
{
    public HelloMetadataModule(ISwaggerModelCatalog modelCatalog, ISwaggerTagCatalog tagCatalog)
        : base(modelCatalog, tagCatalog)
    {
        RouteDescriber.DescribeRoute<ResponseWrapper<FirstResponse>>(
            "op1",
            null,
            "op1",
            new[] { new HttpResponseMetadata<ResponseWrapper<FirstResponse>> { Code = 200, Message = "OK" } },
            null);
        RouteDescriber.DescribeRoute<ResponseWrapper<FirstResponse>>(
            "op2",
            null,
            "op2",
            new[] { new HttpResponseMetadata<ResponseWrapper<SecondResponse>> { Code = 200, Message = "OK" } }, 
            null);
    }
}

public class ResponseWrapper<T>
{
    public T Response { get; set; }
}

public class FirstResponse
{
    public int Int { get; set; }
}

public class SecondResponse
{
    public string Str { get; set; }
}

And here is exception:

Nancy.RequestExecutionException: Oh noes! ---< System.ArgumentException: An item with the same key has already been added.
   at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
   at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
   at Nancy.Swagger.Services.SwaggerMetadataProvider.GetSwaggerJson(NancyContext context)
   at Nancy.Swagger.Modules.SwaggerModule.><c__DisplayClass0_0.>.ctor<b__0(Object _)
   at Nancy.NancyModule.><c__DisplayClass14_0`1.>Get<b__0(Object args)
   at Nancy.NancyModule.><c__DisplayClass16_0`1.>Get<b__0(Object args, CancellationToken ct)
   at Nancy.Routing.Route`1.Invoke(DynamicDictionary parameters, CancellationToken cancellationToken)
   at Nancy.Routing.DefaultRouteInvoker.>Invoke<d__2.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 Nancy.Routing.DefaultRequestDispatcher.>Dispatch<d__5.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 Nancy.NancyEngine.>InvokeRequestLifeCycle<d__22.MoveNext()
   --- End of inner exception stack trace ---
   at Nancy.NancyEngine.InvokeOnErrorHook(NancyContext context, ErrorPipeline pipeline, Exception ex)

I've attached a full linqpad example: nancy-swagger-reproduce.linq.txt

jnallard commented 7 years ago

Ah, it's because of the generics. PR #106 should solve this problem.

@yahehe Maybe we should just merge that PR?

vvreutskiy commented 7 years ago

Ok, so I am waitiog for that PR and closing this.

yahehe commented 7 years ago

@vvreutskiy the version you want now is 2.2.28-alpha