【问题标题】:Json result : Expected ',' instead of ''Json 结果:预期为 ',' 而不是 ''
【发布时间】:2017-07-03 12:15:27
【问题描述】:

对于 api 和 json 序列化,我有点陌生。 我遇到了一个奇怪的输出。似乎我的 json 输出被截断或格式错误?

(我正在使用带有 .net core 2.0 和 entity framework core 2.0 preview2 的 web api)

postman出现如下错误:

Expected ',' instead of ''

但在检查原始数据时,我发现并非所有内容都在发送:

 {
    "id": 2,
    "username": "c8bee98",
    "firstname": "Firstname73",
    "lastname": "Lastname73",
    "creationDate": "2017-07-02T23:47:16.204588",
    "activityDate": "2017-07-03T14:02:58.6982234+02:00",
    "profilePictureURL": "ProfilePictureURL73",
    "gender": 2,
    "location": "POINT(25.1400680863951
    -25.0786780636193)",
    "appsetting": null,
    "email": "Email73",
    "isHidden": false,
    "isBanned": false,
    "feedback": [{
            "id": 19,
            "rating": 1,
            "feedbackType": 0,
            "message": "Message1",
            "creationDate": "2017-07-02T23:47:18.2287331",
            "userId": 2

我的控制器如下所示:

    UserManager userManager = new UserManager();

    [HttpGet]
    public async Task<User> GetById(int id)
    {
        try
        {
            return await userManager.GetByIdAsync(id);
        }
        catch (Exception ex)
        {

            throw ex;
        }
    }

我的模型如下所示:

public class User
{
    [DisplayName("Id")]
    public int Id { get; set; }


    private string username = Guid.NewGuid().ToString("N");

    [Required(ErrorMessage = "Username is required")]
    [DisplayName("Username")]
    [StringLength(32)]
    public string Username
    {
        get {
            string shortusername = username;
            return shortusername.Remove(0,25);
        }
    }
    public string ResetUsername()
    {
        username = Guid.NewGuid().ToString("N");
        return username;
    }

    [Required(ErrorMessage = "Firstname is required")]
    [StringLength(50, ErrorMessage = "Firstname can only be 50 characters long")]
    [DisplayName("Firstname")]
    public string Firstname { get; set; }

    [Required(ErrorMessage = "Lastname is required")]
    [StringLength(50, ErrorMessage = "Lastname can only be 50 characters long")]
    [DisplayName("Lastname")]
    public string Lastname { get; set; }

    [Required(ErrorMessage = "Creation date is required")]
    [DisplayName("Creation Date")]
    [DataType(DataType.Date)]
    [Column(TypeName = "datetime2")]
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd}")]
    public DateTime CreationDate { get; set; } = DateTime.Now;

    [Required(ErrorMessage = "Last activity date could not be registered")]
    [DisplayName("Last Activity Date")]
    [DataType(DataType.Date)]
    [Column(TypeName = "datetime2")]
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd}")]
    private DateTime lastActivityDate;

    public DateTime ActivityDate
    {
        get { return lastActivityDate; }
        set { lastActivityDate = DateTime.Now; }
    }

    [DataType(DataType.ImageUrl)]
    [StringLength(2000, ErrorMessage = "That link is to long!")]
    [DisplayName("Profile Picture")]
    public string ProfilePictureURL { get; set; }

    [Required]
    [DisplayName("Gender")]
    public Gender Gender { get; set; } = Gender.Unknown;

    private string location = "POINT (0 0)";

    [Required]
    [DataType("geography")]
    [DisplayName("Location")]
    public string Location
    {
        get { return location; }
    }

    public string SetLocation(double latitude, double longitude)
    {
        location = String.Format("POINT({0} {1})", longitude, latitude).Replace(',', '.');
        return location;
    }
    public double GetLatitude()
    {
        return double.Parse(location.Split('(', ')')[0].Split(' ')[0]);
    }
    public double GetLongitude()
    {
        return double.Parse(location.Split('(', ')')[0].Split(' ')[1]);
    }

    [DisplayName("App Settings")]
    public AppSetting Appsetting { get; set; }

    [DisplayName("Email")]
    [DataType(DataType.EmailAddress, ErrorMessage = "Invalid email" )]
    [StringLength(320)]
    public string Email { get; set; }
    [Required]
    [DisplayName("Hidden")]
    public bool IsHidden { get; set; } = false;

    [Required]
    [DisplayName("Banned")]
    public bool IsBanned { get; set; } = false;

    //User can have multiple feedbacks
    public IEnumerable<Feedback> Feedback { get; set; }

    //User can have multiple reported users
    public IEnumerable<Reported> ReportedUsers { get; set; }

    //User can have multiple blocked users
    public IEnumerable<Blocked> BlockedUsers { get; set; }

    //User can have multiple connections
    public IEnumerable<Connection> Connections { get; set; }

    //User can have multiple categories
    public IEnumerable<UserCategory> UserCategory { get; set; }

    //User can have multiple roles
    public IEnumerable<UserRole> UserRole { get; set; }

    //User can have multiple messages
    public IEnumerable<Message> Messages { get; set; }

    //User can watch multiple advertisements
    public IEnumerable<Advertisement> Advertisement { get; set; }

    //User can watch multiple advertisements
    public IEnumerable<UserAdvertisement> WatchedAdvertisement { get; set; }

    //User can have multiple providers
    public IEnumerable<UserProvider> UserProvider { get; set; }
}

有什么建议吗?

编辑:

我的反馈集合有 2 个项目(2 个反馈)。

仅显示 1 及其所有属性。

反馈模型:

public class Feedback
{
    [DisplayName("Id")]
    public int Id { get; set; }

    [Required(ErrorMessage = "A rating is required")]
    [DisplayName("Rating")]
    public int Rating { get; set; }

    [Required(ErrorMessage = "A feedbacksection is required")]
    [DisplayName("Section")]
    public FeedbackType FeedbackType { get; set; }

    [DisplayName("Message")]
    //[DataType("nvarchar(500)")]
    [StringLength(500, ErrorMessage = "That message is to long!")]
    public string Message { get; set; }

    [Required(ErrorMessage = "Creation date is required")]
    [DisplayName("Creation Date")]
    [DataType(DataType.Date)]
    [Column(TypeName = "datetime2")]
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd}")]
    public DateTime CreationDate { get; set; } = DateTime.Now;

    [Required]
    [DisplayName("User")]
    public int UserId { get; set; }
    public User User { get; set; }
}

【问题讨论】:

  • 什么没有被发送?收藏品?
  • 是的,但反馈是否有回馈给用户的参考?如果是,那么你有一个循环依赖。用户 -> 反馈 -> 用户 -> 反馈 -> 用户
  • 这就是为什么我说:不要使用 EF 实体作为返回结果。创建不带自引用属性的 ViewModel/Dto,然后对其进行映射(即使用 AutoMapper,但仅适用于 EF 实体 -> Dto。从不来自 Dto -> EF 实体)
  • @Liam 我使用 Core 是因为我在 Amazon AWS 上制作多服务 API 网关(基本上我的 api 变成了 lambda 函数)
  • 发布包括堆栈在内的整个异常可能会提供有关该问题的更多信息

标签: c# json asp.net-core


【解决方案1】:

即使没有自引用异常,它也在发生。

以下示例解决了我的问题。

(感谢@Tseng 和@Liam 将我推向正确的方向)

[HttpGet]
public async Task<string> GetById(int id)
{
    try
    {
        User user = await userManager.GetByIdAsync(id);
        JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings
        {
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore
        };

        return JsonConvert.SerializeObject(user, jsonSerializerSettings); ;
    }
    catch (Exception ex)
    {

        throw ex;
    }
}

如果你想要全局:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().AddJsonOptions(options => 
     options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore);
}

输出:

{
"Id": 2,
"Username": "c8bee98",
"Firstname": "Firstname73",
"Lastname": "Lastname73",
"CreationDate": "2017-07-02T23:47:16.204588",
"ActivityDate": "2017-07-03T15:25:45.294169+02:00",
"ProfilePictureURL": "ProfilePictureURL73",
"Gender": 2,
"Location": "POINT(25.1400680863951 -25.0786780636193)",
"Appsetting": null,
"Email": "Email73",
"IsHidden": false,
"IsBanned": false,
"Feedback": [
    {
        "Id": 19,
        "Rating": 1,
        "FeedbackType": 0,
        "Message": "Message1",
        "CreationDate": "2017-07-02T23:47:18.2287331",
        "UserId": 2
    },
    {
        "Id": 20,
        "Rating": 1,
        "FeedbackType": 0,
        "Message": "Message1",
        "CreationDate": "2017-07-02T23:47:18.2287445",
        "UserId": 2
    }
],
"ReportedUsers": null,
"BlockedUsers": null,
"Connections": null,
"UserCategory": null,
"UserRole": null,
"Messages": null,
"Advertisement": null,
"WatchedAdvertisement": null,
"UserProvider": null
}

【讨论】:

  • 如果解决了,那就是循环引用问题。您可以在 Startup.cs 类中通过services.AddMvc().AddJsonOptions(options =&gt; options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore); 对所有 json 响应执行此操作,然后您不必显式调用序列化程序。但请注意,双重引用将从结果中删除。因此,如果您有订单 -> 用户 -> 订单,“User.Orders”元素将不包括第一个订单(根)。最好使用不带反向引用的 DTO 并从 EF 实体映射到它们
  • 我不确定我帮助了多少,除非创建一个最小的示例可以帮助您解决问题。无论如何,很高兴你到了那里。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多