问题
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.
回答1:
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.
回答2:
This appears to have been a bug related to the Model Substitution feature. The fix has been published in version 3.1.1 of the Microsoft.AspNetCore.OData.Versioning.ApiExplorer package. If this problem persists, please report a new issue in the API Versioning repo.
回答3:
I serialized the response using linq.
This are my classes:
public sealed class ProductDto
{
public int ProductId { get; set; }
public string Description { get; set; }
public string Type { get; set; }
public List<PlanDto> Plans { get; set; }
}
public class PlanDto
{
public int PlanId { get; set; }
public int ProductId { get; set; }
public string Description { get; set; }
public bool Active { get; set; }
public DateTime Created { get; set; }
public virtual ProductDto Product { get; set; }
}
Then I removed from the response the circular reference that in this case is Product = null.
My solution when I'm creating ProductDto Api response:
productEntity.ForEach(i => i.Plans.ForEach(j => j.Product = null));
return productEntity;
When swagger fixes this issue this serialization won't be necessary.
来源:https://stackoverflow.com/questions/53705270/swagger-crashes-with-circular-model-references