循环模型引用使Swagger崩溃

时间:2018-12-10 12:01:56

标签: asp.net-core odata swagger

我有一个.Net Core 2.2 OData API,我想为此实现Swagger文档。

我一直在关注这个示例:https://github.com/Microsoft/aspnet-api-versioning/tree/master/samples/aspnetcore/SwaggerODataSample

我已经做到了一点。 现在,我的模型以循环方式相互引用时遇到一个问题,让我解释一下:

注意:我使用EFCore Code first方法处理数据库。

我有以下模型(作为示例):Project,ProjectLocation,ProjectRegion。 让我们称它们为A,B和C是为了使内容简短。

A对B&C的引用如下:

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

B和C都直接像这样引用A:

public A A{ get; set; }

这都是标准的关系数据库模型,但是SwaggerUI似乎无法处理。

我得到的错误如下:

  

无法加载API定义。   错误:   提取错误:   内部服务器错误/swagger/v1/swagger.json

     

处理请求时发生未处理的异常。   TypeLoadException:无法从程序集“ Tc2fc56a7babe40419a678a075439246c.DynamicModels,版本= 0.0.0.0,文化=中性,PublicKeyToken = null”中加载类型“ NCCRD.Services.DataV2.Database.Models.ProjectLocation”。

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

如果需要,还可以使用堆栈跟踪。

我已尽我所能阅读了这两篇文章和所有参考链接,但找不到有效的解决方案:

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

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

看似好的解决方案是:https://systemout.net/2017/04/07/swagger-asp-net-core-fixing-circular-self-references/,但这也没有任何效果。 (我也联系作者寻求帮助)

从B或C中删除对A的引用后,SwaggerUI就会很好地加载。

如果有人能对此有所启发,我将非常感激。 预先感谢您提供的任何帮助。

3 个答案:

答案 0 :(得分:2)

经过两天的深入研究和实验,我找不到开箱即用的解决方案。 Swashbuckle曾经是我的首选,但是因为我在.NetCore中使用Odata,所以这不是一个选择。 Swashbuckle为OData和.NetCore分别提供了选项,但不幸的是,不能同时使用。

但是我确实找到了一个解决方案,通过我的努力,我能够将其转换为适合我需要的东西。以下帖子构成了我最终解决方案的起点(仍然是一个进行中的BTW):https://stackoverflow.com/a/51774147/4261155

我的“ CustomDocumentFilter”版本已在GitHub上发布:https://github.com/SAEONData/NCCRD/blob/swagger_odata_netcore/NCCRD_API/NCCRD.Services.DataV2/Database/Contexts/CustomDocumentFilter.cs

如前所述,这项工作仍在进行中,因此将在接下来的几天内进行更改,但是与原始版本一起,我希望这可以对处于相同情况的其他人有所帮助。另外请记住,该类经过修改以满足我的特定需求,而不是为其他任何人提供的“开箱即用”的解决方案。

答案 1 :(得分:0)

这似乎是与Model Substitution功能有关的错误。该修补程序已发布在 Microsoft.AspNetCore.OData.Versioning.ApiExplorer 程序包的版本3.1.1中。如果此问题仍然存在,请在API版本库中报告new issue

答案 2 :(得分:0)

我使用linq序列化了响应。

这是我的课程:

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; }
}

然后,我从响应中删除了在这种情况下为 Product = null 的循环引用。

我的解决方案:

productEntity.ForEach(i => i.Plans.ForEach(j => j.Product = null));

当昂首阔步地解决了这个问题时,就不需要序列化了。