C# .net核心:不完整的JSON响应
我正在尝试为培训构建简单的API,在我的数据库中我得到了用户(名字、姓氏、电子邮件密码、C# .net核心:不完整的JSON响应,c#,asp.net-core,.net-core,asp.net-core-mvc,C#,Asp.net Core,.net Core,Asp.net Core Mvc,我正在尝试为培训构建简单的API,在我的数据库中我得到了用户(名字、姓氏、电子邮件密码、list)和运动(名字、用户名)。 当我想要得到我的用户时,我得到了一个填充了运动的对象。但是JSON响应是不完整的,它在中间被“切割”。 [{"firstName":"Nicolas","lastName":"Bouhours","email":"n.bouh@test.com","password":"nico@hotmail.fr","sports":[{"name":"Trail","userId":
list
)和运动(名字、用户名)。
当我想要得到我的用户时,我得到了一个填充了运动的对象。但是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;
}
//GET:api/Users
[HttpGet]
公共IEnumerable GetUsers()
{
var users=_context.users.Include(u=>u.Sports.ToList();
返回用户;
}
我的模特们:
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; }
}
public class Sport:BaseEntity
{
公共字符串名称{get;set;}
public int UserId{get;set;}
公共用户{get;set;}
}
公共类用户:BaseEntity
{
公共字符串名{get;set;}
公共字符串LastName{get;set;}
公共字符串电子邮件{get;set;}
公共字符串密码{get;set;}
公共列表运动{get;set;}
}
公共类SportAppContext:DbContext
{
公共SportAppContext(DbContextOptions):基本(选项)
{ }
公共数据库集用户{get;set;}
公共数据库集运动{get;set;}
}
我真的不明白发生了什么,如果你知道的话,我在我的一个项目中遇到了这个问题。这是由自引用循环引起的 您需要创建某种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; }
}
公共级SportDto
{
公共字符串名称{get;set;}
}
公共类UserDto
{
公共字符串名{get;set;}
公共字符串LastName{get;set;}
公共字符串电子邮件{get;set;}
公共字符串密码{get;set;}
公共列表运动{get;set;}
}
然后将您的用户user
和Sport
型号映射到您的UserDto
和SportDto
进行此映射的一个好工具是。您可以阅读文档以了解如何开始
映射完成后,将DTO作为JSON而不是模型发送。我现在遇到了同样的问题。您还可以更改JSON序列化/配置设置以忽略自引用循环,如接受的答案所示
在我的例子中,这可以通过使用Newtonsoft解决我在core 3上的问题: 在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中打包并配置它
选择的答案在我的例子中也是正确的,我的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; }
}
public class Sport:BaseEntity
{
公共字符串名称{get;set;}
public int UserId{get;set;}
公共用户{get;set;}//这是循环引用的原因
}
公共类用户:BaseEntity
{
公共字符串名{get;set;}
公共字符串LastName{get;set;}
公共字符串电子邮件{get;set;}
公共字符串密码{get;set;}
公共列表运动{get;set;}
}
正如您所看到的,您的用户导航属性就是这个响应被截断的地方。具体来说,它将导致json响应中的每个运动包含响应中每个运动条目的所有用户信息。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; }
}
public class Sport:BaseEntity
{
公共字符串名称{get;set;}
public int UserId{get;set;}
[JsonIgnore]
公共用户用户{get;set;}//已修复
}
公共类用户:BaseEntity
{
公共字符串名{get;set;}
公共字符串LastName{get;set;}
公共字符串电子邮件{get;set;}
公共字符串密码{get;set;}
公共列表运动{get;set;}
}
只是为了添加另一个可能发生这种情况的独特场景。如果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
。。。
RootLevelProp1=“asd”,
RootLevelProp2=“asd”,
Trades=b.Trades.OrderBy(c=>c.Time)。选择(c=>new
{
c、 方向,
c、 价格,
c、 股数,
c、 时间
})//面临类似问题,响应被截断。问题是一个试图格式化日期的getter方法。试试这个:在我的例子中,添加mapping和viewmodel解决了这个问题,这是一个非常好的干净的解决方案,可以解决不完整的json问题。(Y) 这并不能真正回答问题。如果您有不同的问题,可以单击以提问。一旦你有足够的时间,你也可以吸引更多的注意力-
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; }
}
...
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