如何停止 .Net Core Web API 中的自引用循环?
Posted
技术标签:
【中文标题】如何停止 .Net Core Web API 中的自引用循环?【英文标题】:How to stop self-referencing loop in .Net Core Web API? 【发布时间】:2017-07-20 04:33:10 【问题描述】:我遇到了一些问题,我猜这些问题与使用 .NET Core Web API 和 Entity Framework Core 进行自我引用有关。添加 .Includes 用于某些导航属性时,我的 Web API 开始阻塞。
我在旧的 Web API 中找到了一个解决方案,但我不知道如何为 .NET Core Web API 实现相同的东西(我仍处于早期学习阶段)。
较旧的解决方案将其粘贴在 Global.asax 的 Application_Start() 中:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
我怀疑这是在 StartUp 的 ConfigureService() 方法中处理的,但除此之外我知道的不多。
或者有没有更合适的方法来处理这个问题?
【问题讨论】:
一般来说,我使用没有循环的 API 对象(不是直接的 EF 对象) @BradleyDotNET 我同意,将您的数据库映射到以 API 调用者为中心的连线对象。 DB over a wire 是软件开发的反模式(具有讽刺意味的是,对于许多“做 REST”的人来说,它是一个 goto 解决方案) 这似乎违反了 DRY 原则,因为我的线模型看起来与 EF 填充的模型相同。 @SailingJudo 真正的问题是他们应该这样做吗?一般来说,API 对象可以比关系数据库所需的更扁平 【参考方案1】:好的...我终于找到了一些关于此的参考资料。解决办法是:
public void ConfigureServices(IServiceCollection services)
...
services.AddMvc()
.AddJsonOptions(
options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
...
我从here得到这个
【讨论】:
非常感谢...这让我发疯了。我有同样的问题。我觉得转换为json时应该默认处理。 这在 .NetCore 3 中发生了变化。请参阅this awnser。也许您可以将其添加到您的答案中。【参考方案2】:如果您使用的是 ASP.NET Core 3.0,并且遇到该问题,请安装 NuGET 包:Microsoft.AspNetCore.Mvc.NewtonsoftJson 3.0.0。。 p>
要替换尚没有引用循环处理的新 System.Text.Json,请在 Startup.cs 中执行此操作,确保在 ConfigureServices 中包含:
如果使用最新的.Net Core 3.0方式:
services.AddControllers().AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
);
或旧方法:
services.AddMvc(option => option.EnableEndpointRouting = false)
.AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore)
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
【讨论】:
我如何使用 System.Text.JSON 做到这一点 正如我提到的,Text.JSON 尚不支持它 如果有人知道如何使用 .AddControllersWithViews() lmk 进行这种链接,我无法找到方法。 我一直在SerializerSettings
上遇到错误,所以我一直在寻找替换这些选项的方法,但结果我使用的是旧的(?)AddJsonOptions
,却没有意识到我需要替换它与AddNewtonsoftJson
。一旦我这样做了,我就可以再次使用SerializerSettings
并在升级旧项目时保留旧功能。这次真是万分感谢!我花了几个小时试图弄清楚这一点。【参考方案3】:
ReferenceLoopHandling.Ignore “隐藏”问题,而不是解决问题。您真正需要做的是构建图层。创建域对象以位于您的实体之上,并将它们包装在某种服务/业务层中。查找存储库模式并在有帮助的情况下应用它。您需要在实体和域对象之间进行映射,这使您有机会适应某种映射器(自动映射器)和验证层..
如果您的域对象和实体完全相同,那么您需要更多地考虑您在做什么。
例如:您的实体是否有软删除? (IsDeleted) 标志?如果是这样,这不一定需要通过网络返回给客户端,所以这是一个完美的例子,说明它们会有所不同。
不管怎样,答案不是用 JSON 覆盖它,而是改变你的架构..
【讨论】:
只是好奇,但这样做的理由是什么?使用域实体而不是将它们重新创建为 DTO 的问题在哪里(我假设您所说的“实体”是什么意思)?有时它更容易(即使使用我使用的存储库模式),特别是如果您有很多域实体并且如果这些实体在您已经想在客户端上使用的模式中。我想知道“我”在这里做错了什么。 域对象中通常包含业务逻辑。例如,它可以从“FirstName”和“Surname”中组合“Display Name”之类的属性。DTO 将希望“干净” ” 尽可能.. 部分是为了序列化,但也因为它使整个事务更清晰,因为调用者只想查看他们需要操作哪些字段以通过网络来回传递有效对象。根据您的情况,它可能是纯粹的语义 - 但域对象和 DTO 之间存在明确的区别以上是关于如何停止 .Net Core Web API 中的自引用循环?的主要内容,如果未能解决你的问题,请参考以下文章
如何解决请求与 .Net Core Web Api 中的多个端点匹配的问题
如何从 ASP.NET Core Web API 中的 SQL Server 存储过程中获取返回值
如何通过 ASP.NET Core 3 中的中间 Web API 传递未更改的 HTTP 响应?
EF Core 5.0 - 更新 ASP.NET Core Web API 中的多对多实体