简体   繁体   English

Web API2序列化异常

[英]Web API2 Serialization exception

I have a web api2 application which I have scaffolded using EF. 我有一个使用EF搭建的Web api2应用程序。

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). 在我的专业类中没有两个导航属性(Doctors,MedicalFacilities)之前,我没有这个错误。

Any help is much appreciated. 任何帮助深表感谢。

Just a quick recap - why are you returning IQueryable and your entity model as a result? 简要回顾一下-为什么要返回IQueryable和您的实体模型?

In my opinion you should transform your entity model to some kind of DTO with only needed properties + change action signature to IEnumerable<T> . 我认为您应该将实体模型转换为仅需要属性的某种DTO,并将动作签名更改为IEnumerable<T>

What serializer doesn't know is how to serialize dynamic proxies EF creates for your virtual properties. 序列化器不知道的是如何序列化EF为您的virtual属性创建的动态代理。

Please enter following code snippet in webconfig: 请在webconfig中输入以下代码段:

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

The reason might be your navigation properties are Interface so when you access the service it doesnt know what concrete type to use. 原因可能是您的导航属性是Interface,所以当您访问服务时它不知道要使用哪种具体类型。 How about change that to List see if that help? 将该列表更改为List看看是否有帮助呢?

Use Serializable() attribute. 使用Serializable()属性。 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; }
    }
} 

In the end what finally worked was disabling ProxyCreationEnabled. 最后,最后起作用的是禁用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(). 这确实意味着我将不得不渴望使用.include()加载我要使用的所有导航属性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM