Norman Bentley
Norman Bentley

Reputation: 660

Web API2 Serialization exception

I have a web api2 application which I have scaffolded using EF.

I am trying to serialize the following class (Which contains lazy loaded navigation properties):

namespace Models
{
    public class Speciality
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int SpecialityId { get; set; }

        public string Name { get; set; }

        public virtual ICollection<Doctor> Doctors { get; set; }
        public virtual ICollection<MedicalFacility> MedicalFacilities { get; set; }
    }
} 

The is my controller:

namespace FindAMedicService.Controllers
{

    public class SpecialitiesController : ApiController
    {
        private ApplicationDbContext db = new ApplicationDbContext();

        // GET: api/Specialities
        public IQueryable<Speciality> GetSpeciality()
        {
            return db.Speciality;
        }
    }
}

When I try to access this particular service to get a list of "Specialities", I get the following error:

<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace/>
<InnerException>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Type 'System.Data.Entity.DynamicProxies.Speciality_DC264D6DBBAF52FB19E27F20DCC47DA1141620CEC0CCAF6E2DEF4D8907FA7C8C' with data contract name 'Speciality_DC264D6DBBAF52FB19E27F20DCC47DA1141620CEC0CCAF6E2DEF4D8907FA7C8C:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' is not expected. Consider using a DataContractResolver if you are using DataContractSerializer or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to the serializer.
</ExceptionMessage>
<ExceptionType>
System.Runtime.Serialization.SerializationException
</ExceptionType>
<StackTrace>
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, Boolean verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiType(XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle objectTypeHandle, Type objectType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, Type declaredType) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle) at WriteArrayOfSpecialityToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , CollectionDataContract ) at System.Runtime.Serialization.CollectionDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle) at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.DataContractSerializer.WriteObject(XmlWriter writer, Object graph) at System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content) at System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken) --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__1b.MoveNext()
</StackTrace>
</InnerException>
</Error>

I didn't have this error before when I did not have the two navigation properties in my Speciality class (Doctors, MedicalFacilities).

Any help is much appreciated.

Upvotes: 2

Views: 908

Answers (5)

BehrouzMoslem
BehrouzMoslem

Reputation: 9703

Please enter following code snippet in webconfig:

var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreservReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);

Upvotes: 1

Norman Bentley
Norman Bentley

Reputation: 660

In the end what finally worked was disabling ProxyCreationEnabled.

So in my controller I now have the following code:

public class SpecialitiesController : ApiController
    {
        private ApplicationDbContext db = new ApplicationDbContext();

        public SpecialitiesController()
        {
            db.Configuration.ProxyCreationEnabled = false;
        }

        // GET: api/Specialities
        public IQueryable<Speciality> GetSpeciality()
        {
            return db.Speciality;
        }
    }

This does mean that I will have to eager load any navigational properties that I want to use using .include().

Upvotes: 0

Gagan Jaura
Gagan Jaura

Reputation: 719

Use Serializable() attribute. Try this:

namespace Models
{
    [Serializable]
    public class Speciality
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int SpecialityId { get; set; }

        public string Name { get; set; }

        public virtual ICollection<Doctor> Doctors { get; set; }
        public virtual ICollection<MedicalFacility> MedicalFacilities { get; set; }
    }
} 

Upvotes: 0

kamil-mrzyglod
kamil-mrzyglod

Reputation: 4998

Just a quick recap - why are you returning IQueryable and your entity model as a result?

In my opinion you should transform your entity model to some kind of DTO with only needed properties + change action signature to IEnumerable<T>.

What serializer doesn't know is how to serialize dynamic proxies EF creates for your virtual properties.

Upvotes: 2

duongthaiha
duongthaiha

Reputation: 855

The reason might be your navigation properties are Interface so when you access the service it doesnt know what concrete type to use. How about change that to List see if that help?

Upvotes: 0

Related Questions