来自控制器的格式错误的 Json 响应

Posted

技术标签:

【中文标题】来自控制器的格式错误的 Json 响应【英文标题】:Badly formatted Json response from controller 【发布时间】:2018-03-14 18:31:27 【问题描述】:

使用 Asp.net 核心创建 Web api。我正在创建的端点将返回所有客户的列表(目前我只为 1 个客户播种了数据库)。 当我从 Postman 执行 GET 请求时,我收到“无法获得任何响应”。 当我通过 Chrome 导航到该端点时,我看到了响应,但返回的 json 似乎缺少括号。

[

    "customerId":1,
    "firstName":"John",
    "lastName":"Doe",
    "email":"johndoe@email.com",
    "address": 
        "addressId":1,
        "addressLine1":"2119 Some street",
        "addressLine2":null,
        "locality":"New York",
        "region":"New York",
        "country":"USA",
        "postCode":"10005",
        "customerId":1

我想知道格式错误的 Json 响应是否是 Postman 无法正常工作的原因。我想了解什么是错的。在我的简单示例中,我做错了什么可能导致我头痛。

我的仓库:

public class LodgingRepository : ILodgingRepository

    private readonly LodgingCrmContext _context;

    public LodgingRepository( LodgingCrmContext context )
    
        _context = context;
    

    public async Task<IEnumerable<Customer>> GetCustomersAsync( )
    
        return await _context.Customers
            .Include( c => c.Address )
            .ToListAsync( );
    

我的控制器

[Route( "api/customers" )]
public class CustomerController : Controller

    private readonly ILodgingRepository _lodgingRepository;

    public CustomerController( ILodgingRepository lodgingRepository )
    
        _lodgingRepository = lodgingRepository;
    

    [HttpGet]
    public async Task<IActionResult> GetCustomersAsync( )
    
        return Ok( await _lodgingRepository.GetCustomersAsync( ) );
    

启动

public void ConfigureServices( IServiceCollection services )
    
        services.AddMvc( ).AddMvcOptions( options =>
            options.OutputFormatters.Add( new XmlDataContractSerializerOutputFormatter( ) ) );

        services.AddDbContext<LodgingCrmContext>( options =>
            options.UseSqlServer( Configuration.GetConnectionString( "DefaultConnection" ) ) );

        services.AddScoped<ILodgingRepository, LodgingRepository>( );
    

public void Configure( IApplicationBuilder app, IHostingEnvironment env, LodgingCrmContext lodgingCrmContext )
    
        if( env.IsDevelopment( ) )
        
            app.UseDeveloperExceptionPage( );
        

        app.UseMvc( );

        app.Run( async ( context ) =>  await context.Response.WriteAsync( "Hello World!" );  );
    

地址实体

public class Address

    [Key]
    [DatabaseGenerated( DatabaseGeneratedOption.Identity )]
    public int AddressId  get; set; 

    [Required]
    [MaxLength( 254 )]
    public string AddressLine1  get; set; 

    [MaxLength( 254 )]
    public string AddressLine2  get; set; 

    [Required]
    [MaxLength( 60 )]
    public string Locality  get; set; 

    [Required]
    [MaxLength( 50 )]
    public string Region  get; set; 

    [Required]
    [MaxLength( 60 )]
    public string Country  get; set; 

    [Required]
    [MaxLength( 9 )]
    public string PostCode  get; set; 

    [ForeignKey( nameof(CustomerId) )]
    public int CustomerId  get; set; 

    public Customer Customer  get; set; 

【问题讨论】:

你需要枚举集合 在我的控制器中,我对返回的集合做了一个 .ToList() 但得到了相同的结果 GetCustomersAsync 返回IEnumerable 是的,我尝试过的其中一件事是 var customers = await _lodgingRepository.GetCustomersAsync( );返回确定(customers.ToList()); 那还是不行? 【参考方案1】:

问题是每次响应尝试序列化地址时,它都会反弹关联的客户,然后循环重复。这会导致堆栈溢出。

如果您查看 JSON,您会发现它停止了,就像它必须再次访问客户一样

从服务返回时创建 DTO 并将实体映射到它们,以避免通过 EF 导航属性进行循环引用。

[HttpGet]
public async Task<IActionResult> GetCustomersAsync() 
    var records = await _lodgingRepository.GetCustomersAsync();
    var model = await ConvertToDTO(records); //<-- perform convertions here
    return Ok(model);

【讨论】:

以上是关于来自控制器的格式错误的 Json 响应的主要内容,如果未能解决你的问题,请参考以下文章

使用 JSON Sanitizer 清理来自 Spring MVC 控制器的响应 JSON?

返回 json 格式响应

是否有任何适当的匹配器来解析和比较来自 MockMvc 的 Json 响应中的 LocalDateTime 字段

将来自 Axios 的 JSON 响应传递给数据对象但出现错误

学习小片段——springboot 错误处理

来自具有特定“接受”标头的请求的错误响应正文格式