Dear Deer
Dear Deer

Reputation: 543

REST API returns "bad array" instead of JSON object

I'm building REST API server in .NET core. I'm testing my code via Postman software. I have a problem with Include() method that enables me to attach navigation property data. I'm trying to get data in [HttpGet] action and objects that are being returned are wrong.

My code : MODELS

Session model

public class Session
    {
        [Key]
        public int IDSession { get; set; }
        [Required]
        public DateTime LogInTime { get; set; }
        public DateTime LogOutTime { get; set; }

        [Required]
        public int IDUser { get; set; }
        public User User { get; set; }

        [Required]
        public int IDMachine { get; set; }
        public Machine Machine { get; set; }
    }

User model

public class User
    {
        [Key]
        public int IDUser { get; set; }
        [Required]
        public string Forename { get; set; }
        [Required]
        public string Name { get; set; }
        public string AvatarPath { get; set; }
        public string Email { get; set; }
        public string PhoneNumber { get; set; }
        public string Password { get; set; }
        public User CreatedBy { get; set; }
        public DateTime CreatedAt { get; set; }

        public List<UserGroup> UsersGroups { get; set; }
        public List<Alarm> ExecutedAlarms { get; set; }
        public List<Alarm> ResetedAlarms { get; set; }
        public List<AccessCard> Cards { get; set; }
        public List<AccessCard> UserCardsAdded { get; set; }
        public List<User> UsersAdded { get; set; }
        public List<Session> Sessions { get; set; }
        public List<EventsLog> Events { get; set; }
        public List<Reference> References { get; set; }
        public List<UserPermission> UsersPermissions { get; set; }
    }

Session controller

[Produces("application/json")]
    [Route("api/Sessions")]
    public class SessionsController : Controller
    {
        private readonly DBContext _context;

        #region CONSTRUCTOR

        public SessionsController(DBContext context)
        {
            _context = context;
        }

        #endregion

        #region HTTP GET

        // GET: api/sessions        
        [HttpGet]
        public async Task<IActionResult> GetSessions()
        {
            var sessions = await _context.Sessions.Include(s => s.User). ToListAsync();

            if (sessions.Any())
            {
                return new ObjectResult(sessions);
            }
            else
            {
                return NotFound();
            }
        }

        // GET: api/sessions/1
        [HttpGet("{id}", Name = "GetSessionByID")]
        public async Task<IActionResult> GetSessionByID(Int32 id)
        {
            var session = await _context.Sessions.Include(s => s.User).FirstOrDefaultAsync(s => s.IDSession == id);

            if (session == null)
            {
                return NotFound();
            }
            else
            {
                return new ObjectResult(session);
            }
        }

        #endregion
}

The idea is that User model contains List<Session> collection that he/she created. I want to be able to return users with its sessions Of course Session model contains a single User because every session is related with a specific, single User. Now, when I need to get all sessions objects in SessionController with GetSessions() or GetSessionsByID() I use POSTMAN [HttpGet] action like this : http://localhost:8080/api/sessions which returns me wrong data :

pretty raw

A session contains a user and in turn a single user is related with its sessions. It looks like it tries to return me Session object properly, includes User object but then it tries to include all sessions for that User. That's not what I want. It looks like some kind of a loop. Sessions shoud be returned with its User objects and that's it. How can I achieve that ? Am I doing some logical mistake in my models ?

Thanks !

Upvotes: 3

Views: 2463

Answers (1)

Dasikely
Dasikely

Reputation: 625

I met also this issue recently. So, I've fixed it by adding this script in the Startup.cs file and ConfigureServices method :

services.AddMvc().AddJsonOptions(
            options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
        );

So, you suffix services.AddMvc() by this code who means that you have to make JSON.Net to ignore cycles finded to the nested object request. And of course having Newtonsoft.Json package installed to your project and referenced in each concerned file

For much clearer information, see this link at Related Data and Serialization section : https://learn.microsoft.com/en-us/ef/core/querying/related-data

Hope this is helpfull for you

Upvotes: 6

Related Questions