.net core:不完整的JSON响应
.net core:不完整的JSON响应
我正在尝试构建一个简单的用于训练的API,在我的数据库中有用户(名字、姓氏、电子邮件、密码、list
)和运动(名称、用户ID)。当我想获取我的用户时,一切都正常,我得到一个已填充运动数据的对象。但是JSON响应是不完整的,它在中间被“截断”了。
下面是我的控制器:
// GET: api/Users [HttpGet] public IEnumerableGetUsers() { 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 ListSports { get; set; } } public class SportAppContext : DbContext { public SportAppContext(DbContextOptions options) : base(options) { } public DbSet Users { get; set; } public DbSet Sports { get; set; } }
我真的不明白发生了什么,如果你有任何想法。
在这个问题中,出现了一个特殊的情况。如果您的数据访问层(DAL)返回的是可查询对象(queryables),也会发生这种情况。在我的情况中,我从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
尽管对根对象调用了.ToListAsync()
,但查询Trades
从未被执行。问题在于,控制器返回的结果只包括Trades
部分,而JSON没有正确地终止。后来我意识到,在我编写的某个自定义中间件中捕获到了一个异常,该异常抱怨数据读取器已经打开。在没有深入调查的情况下,我假设这与依赖注入(DI)以及它如何处理上下文的生命周期有关。解决方法就是在Trades
后面添加ToList
。这是一种不太优雅的方式来传递DAL中的数据,但这只是一个有趣的项目。
问题:.net core中的不完整JSON响应
原因:在序列化JSON时,可能会出现对象之间的循环引用,导致序列化过程中出现问题。
解决方法:可以通过更改JSON序列化/配置设置来忽略自引用循环。具体方法如下:
在ConfigureServices方法中添加以下代码:
public void ConfigureServices(IServiceCollection services) { services.AddMvc().AddJsonOptions(options => { options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; }); }
这样就可以解决不完整JSON响应的问题了。
在我的一个项目中,我也遇到了这个问题。这是由于自引用循环引起的。
你需要创建某种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 ListSports { get; set; } }
然后将你的用户模型 `User` 和运动模型 `Sport` 映射到你的 `UserDto` 和 `SportDto`。
一个很好的工具用于进行这种映射是 AutoMapper。你可以阅读文档了解如何入门。
映射完成后,你将发送DTO作为你的JSON,而不是你的模型。