我正在尝试构建简单的API用于培训,在我的数据库中我获得了用户(名字,姓氏,电子邮件密码,list<sports>
)和体育(名称,用户ID)。
一切都没关系,当我想要获得我的用户时,我得到了一个填充了体育的对象。但是JSON响应是不完整的,它在中间被“切断”。
[{"firstName":"Nicolas","lastName":"Bouhours","email":"n.bouh@test.com","password":"nico@hotmail.fr","sports":[{"name":"Trail","userId":1
这是我的控制者:
// GET: api/Users
[HttpGet]
public IEnumerable<User> GetUsers()
{
var users = _context.Users.Include(u => u.Sports).ToList();
return users;
}
我的模特:
public class Sport : BaseEntity
{
public string Name { get; set; }
public int UserId { get; set; }
public User User { get; set; }
}
public class User : BaseEntity
{
public String FirstName { get; set; }
public String LastName { get; set; }
public String Email { get; set; }
public String Password { get; set; }
public List<Sport> Sports { get; set; }
}
public class SportAppContext : DbContext
{
public SportAppContext(DbContextOptions<SportAppContext> options) : base(options)
{ }
public DbSet<User> Users { get; set; }
public DbSet<Sport> Sports { get; set; }
}
我真的不明白发生了什么,如果你有任何想法
答案 0 :(得分:7)
我现在遇到同样的问题。您还可以更改JSON序列化/配置设置以忽略自引用循环,如接受的答案for this question
中所示public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().AddJsonOptions(options => {
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
}
答案 1 :(得分:6)
我在其中一个项目中遇到过这个问题。这是由自引用循环引起的。
您需要创建一些DTO(数据传输对象),用于生成JSON。
在您的DTO中删除反向关系,以便最终得到类似
的内容 public class SportDto
{
public string Name { get; set; }
}
public class UserDto
{
public String FirstName { get; set; }
public String LastName { get; set; }
public String Email { get; set; }
public String Password { get; set; }
public List<SportDto> Sports { get; set; }
}
然后,您将用户User
和Sport
模型映射到UserDto
和SportDto
执行此映射的一个好工具是AutoMapper。您可以阅读文档以了解如何开始。
映射完成后,您将 DTOs 作为JSON发送,而不是模型。
答案 2 :(得分:0)
就我而言,这可以通过使用Newtonsoft解决我在核心3上的问题: https://docs.microsoft.com/en-us/aspnet/core/web-api/advanced/formatting?view=aspnetcore-3.0#add-newtonsoftjson-based-json-format-support
在ASP.NET Core 3.0之前,默认使用的JSON格式化程序 使用Newtonsoft.Json包实现。在ASP.NET Core 3.0中或 稍后,默认的JSON格式器基于System.Text.Json。 支持基于Newtonsoft.Json的格式化程序和功能 通过安装Microsoft.AspNetCore.Mvc.NewtonsoftJson NuGet 包并在Startup.ConfigureServices中对其进行配置。
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers()
.AddNewtonsoftJson();
}
答案 3 :(得分:0)
在我看来,选择的答案也是正确的,我的JSON响应被JSON响应中的引用循环截断,并设置ReferenceLoopHandling.Ignore确实解决了我的问题。但是,这并不是我认为的最佳解决方案,因为这可以在模型中维护循环引用。更好的解决方案是在模型中使用[JsonIgnore]属性。
模型中的问题在这里:
public class Sport : BaseEntity
{
public string Name { get; set; }
public int UserId { get; set; }
public User User { get; set; } //This is the cause of your circular reference
}
public class User : BaseEntity
{
public String FirstName { get; set; }
public String LastName { get; set; }
public String Email { get; set; }
public String Password { get; set; }
public List<Sport> Sports { get; set; }
}
如您所见,您的“用户”导航属性是该响应被截断的地方。具体来说,它将导致json响应中的每个Sport包含响应中每个Sport条目的所有用户信息。 Newtonsoft不喜欢这样。解决方案是简单地[JsonIngore]导致此循环引用的导航属性。在您的代码中,这将是:
public class Sport : BaseEntity
{
public string Name { get; set; }
public int UserId { get; set; }
[JsonIgnore]
public User User { get; set; } //fixed
}
public class User : BaseEntity
{
public String FirstName { get; set; }
public String LastName { get; set; }
public String Email { get; set; }
public String Password { get; set; }
public List<Sport> Sports { get; set; }
}
答案 4 :(得分:0)
只需添加另一个可能发生这种情况的方案即可。如果您的DAL返回可查询对象,也会发生这种情况。在我的场景中,我从DAL返回了一个装箱的对象,并且有类似linq查询的内容
...
RootLevelProp1 = "asd",
RootLevelProp2 = "asd",
Trades = b.Trades.OrderBy(c => c.Time).Select(c => new
{
c.Direction,
c.Price,
c.ShareCount,
c.Time
}) //<---- This was being returned as a queryable to the controller
Trades
查询从未执行过,即使其根对象调用了.ToListAsync()
。发生的事情是,控制器将返回结果,但仅返回Trades
节,并且Json无法正确终止。然后,我意识到在我编写的某些自定义中间件中捕获了一个异常,它抱怨数据读取器已经打开。在不深入调查的情况下,我认为它必须对DI以及它如何处理上下文的生命周期进行某些处理。解决方法是仅在交易中添加ToList
。从DAL传递数据是一种丑陋的方式,但这只是一个有趣的项目。
答案 5 :(得分:-1)
面对类似的问题,响应被截断了。问题是尝试格式化日期的吸气剂方法。