Search code examples
asp.net-coreodataswagger

Swagger crashes with circular model references


I have a .Net Core 2.2 OData API, for which I'm tying to implement Swagger documentation.

I've been following this example: https://github.com/Microsoft/aspnet-api-versioning/tree/master/samples/aspnetcore/SwaggerODataSample

I've got it working up to a point. Now I'm facing an issue with my models referencing each other in a circular manner, let me explain:

Note: I used EFCore Code first approach for handling my DB.

I have these models (as an example): Project, ProjectLocation, ProjectRegion. Lets call them A, B & C to keep things short.

A has references to B & C like so:

public virtual ICollection<X> X{ get; set; }

And both B & C reference A directly like so:

public A A{ get; set; }

This is all pretty standard relational DB model stuff, but it seems SwaggerUI can't handle this.

The error I'm getting is as follows:

Failed to load API definition. Errors: Fetch error: Internal Server Error /swagger/v1/swagger.json

An unhandled exception occurred while processing the request. TypeLoadException: Could not load type 'NCCRD.Services.DataV2.Database.Models.ProjectLocation' from assembly 'Tc2fc56a7babe40419a678a075439246c.DynamicModels, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.

System.Signature.GetSignature(Void* pCorSig, int cCorSig, RuntimeFieldHandleInternal fieldHandle, IRuntimeMethodInfo methodHandle, RuntimeType declaringType)

A stack-trace is also available if needed.

I've read these two posts and all of the references links as far as I could go, but did not find a solution that works:

https://github.com/swagger-api/swagger-codegen/issues/741

https://github.com/swagger-api/swagger-codegen/issues/728

Once solution that seemed good was this: https://systemout.net/2017/04/07/swagger-asp-net-core-fixing-circular-self-references/, but this too had no effect. (I contacted to author for help too)

The moment I remove the reference to A from either B or C, then SwaggerUI loads up fine.

If anyone could shed some light on this I'd really appreciate it. Thanks in advance to any help offered.


Solution

  • After two days of intense research and experimentation, I was unable to find any solutions that work out of the box. Swashbuckle used to be my goto for this, but because I'm using Odata in .NetCore that's not an option. Swashbuckle offers options for OData and .NetCore separately, but unfortunately not when used together.

    I did however find a solution, that with some effort I was able to convert into something that works for my needs. The following post formed the starting point of my eventual solution (which is still a work-in-progress BTW): https://stackoverflow.com/a/51774147/4261155

    My version of "CustomDocumentFilter" is up on GitHub: https://github.com/SAEONData/NCCRD/blob/swagger_odata_netcore/NCCRD_API/NCCRD.Services.DataV2/Database/Contexts/CustomDocumentFilter.cs

    As mentioned, this is still a work in progress so it'll be changing over the next few days, but together with the original version, I'm hoping this might help someone else in this same situation. Also keep in mind, this class was adapted to suit my specific needs, and is not intended as an "out of the box" solution for anyone else.