0

I am stumped on this for a couple of hours.

I am using WebApi 2 and Entity Framework 6.1.3. I am following this tutorial: https://learn.microsoft.com/en-us/aspnet/web-api/overview/data/using-web-api-with-entity-framework/

I would like to return only json. When I hit url http://localhost:11440/Api/Contacts. I am getting following error: The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.

I have the following models and controller defined:

Address.cs

namespace Blah_Application.Models
{
    public class Address
    { 
        public int AddressID { get; set; }

        public int ContactID { get; set; }

        public string Street { get; set; }

        public string City { get; set; }

        public string State { get; set; }

        public string Country { get; set; }

        public string ZipCode { get; set; }

        public double Latitude { get; set; }

        public double Longitude { get; set; }

        public virtual Contact Contact { get; set; }
    }
}

Contact.cs

using System.Collections.Generic;

namespace Blah_Application.Models
{
    public class Contact
    {
        public Contact()
        {
            Phones = new HashSet<Phone>();
            Addresses = new HashSet<Address>();
        }

        public int ContactID { get; set; }

        public string Name { get; set; }

        public string Company { get; set; }

        public bool Favorite { get; set; }

        public string SmallImageUrl { get; set; }

        public string LargeImageUrl { get; set; }

        public string Email { get; set; }

        public string Website { get; set; }

        public string BirthDate { get; set; }

        public virtual ICollection<Phone> Phones { get; set; }

        public virtual ICollection<Address> Addresses { get; set; }
    }
}

Phone.cs

namespace Ecitslos_Application.Models
{
    public enum PhoneType { Home, Work, Mobile}

    public class Phone
    {
        public int PhoneID {get; set;}

        public int ContactID { get; set; }

        public PhoneType PhoneType { get; set; }

        public string Number { get; set; }

        public virtual Contact Contact { get; set; }
    }
}

ContactsController.cs

using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq; 
using System.Net;
using System.Web.Http;
using System.Web.Http.Description;
using Blah_Application.Models;

namespace Ecitslos_Application.Controllers
{
    public class ContactsController : ApiController
    {
        private Ecitslos_ApplicationContext db = new 
        Ecitslos_ApplicationContext();

        // GET: api/Contacts
        public IQueryable<Contact> GetContacts()
        {
            return db.Contacts;
        }

        // GET: api/Contacts/5
    [ResponseType(typeof(Contact))]
    public IHttpActionResult GetContact(int id)
    {
        Contact contact = db.Contacts.Find(id);
        if (contact == null)
        {
            return NotFound();
        }

        return Ok(contact);
    }

    // PUT: api/Contacts/5
    [ResponseType(typeof(void))]
    public IHttpActionResult PutContact(int id, Contact contact)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        if (id != contact.ContactID)
        {
            return BadRequest();
        }

        db.Entry(contact).State = EntityState.Modified;

        try
        {
            db.SaveChanges();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!ContactExists(id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }

        return StatusCode(HttpStatusCode.NoContent);
    }

    // POST: api/Contacts
    [ResponseType(typeof(Contact))]
    public IHttpActionResult PostContact(Contact contact)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        db.Contacts.Add(contact);
        db.SaveChanges();

        return CreatedAtRoute("DefaultApi", new { id = contact.ContactID }, contact);
    }

    // DELETE: api/Contacts/5
    [ResponseType(typeof(Contact))]
    public IHttpActionResult DeleteContact(int id)
    {
        Contact contact = db.Contacts.Find(id);
        if (contact == null)
        {
            return NotFound();
        }

        db.Contacts.Remove(contact);
        db.SaveChanges();

        return Ok(contact);
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            db.Dispose();
        }
        base.Dispose(disposing);
    }

    private bool ContactExists(int id)
    {
        return db.Contacts.Count(e => e.ContactID == id) > 0;
    }
    }
}
hikerclimb
  • 21
  • 4

2 Answers2

0

You need to disable the XML formatter that is configured by default. Add the following line to the WebApiConfig class:

public static class WebApiConfig {
    public static void Register(HttpConfiguration config) {
        //route config etc. goes here

        //disable xml serialization
        config.Formatters.Remove(config.Formatters.XmlFormatter);

        //prevent infinite recusion
        config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
    }
}
user2880616
  • 255
  • 3
  • 12
  • this doesn't work for me. When I try I am getting error:Self referencing loop detected for property 'Contact' with type 'System.Data.Entity.DynamicProxies.Contact_F0D869DA35A5D79D9FC7459ECA71E46F93E7CACF4EB08F9DCCF7A7DCCF99E1D3 – hikerclimb Aug 13 '17 at 21:57
  • @hikerclimb That's a separate issue from returning only JSON. I have edited my answer to include a second configuration setting to handle that. – user2880616 Aug 14 '17 at 01:54
  • @hikerclimb is it because you have `Contact` in `Phone` and then you are instantiating `Phone` in `Contact` ? – Allen King Aug 14 '17 at 01:56
0

Way I am doing this in my project is the following. Hope you can get a pointer in the right direction.

 // GET: api/Contacts/5
    <Route("~/api/Contacts/{id}")>
    <HttpGet>
    public HttpResponseMessage GetContact(int id)
    {
        Contact contact = db.Contacts.Find(id);
        if (contact == null)
        {
            Return Request.CreateResponse(HttpStatusCode.NotFound, "Contact Id not found", Configuration.Formatters.JsonFormatter);
        }
Return Request.CreateResponse(HttpStatusCode.OK, contact, Configuration.Formatters.JsonFormatter);

    }

Also, you have Contact in Phone and then you are instantiating Phone in Contact. This may create a cyclic dependency.

Allen King
  • 2,372
  • 4
  • 34
  • 52