2015-09-30 268 views
2

我有一個web api2應用程序,我用腳手架使用EF。Web API2序列化異常

我試圖序列化下面的類(包含延遲加載導航性能):

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; } 
    } 
} 

的是我的控制器:

namespace FindAMedicService.Controllers 
{ 

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

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

當我試圖訪問這個特殊的服務來獲得一個「專業」列表,我得到以下錯誤:

<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> 

我沒有'當我在我的Specialty類(Doctors,MedicalFacilities)中沒有這兩個導航屬性之前,就有這個錯誤。

任何幫助,非常感謝。

+0

當您嘗試'返回db.Speciality.ToList()會發生什麼;'? – sed

回答

0

原因可能是您的導航屬性是界面,所以當您訪問服務時,它不知道具體的使用類型。如何改變這個列表看看是否有幫助?

+0

他們沒有交流。他們是實際實施的類 –

2

只是一個快速回顧 - 你爲什麼返回IQueryable和你的實體模型?

在我看來,你應該將你的實體模型轉換爲某種DTO,只需要屬性+更改動作簽名到IEnumerable<T>

什麼序列化器不知道如何序列化動態代理EF創建爲您的virtual屬性。

+0

謝謝。我只是使用IQueryable,因爲它像腳手架一樣,並且以前用過。 但是你想要序列化虛擬屬性。那麼是否可以發送包含其他類的類?我應該刪除虛擬?或者添加一個.include語句來顯式添加導航屬性? –

+0

@NormanBentley您應該提供某種從實體模型到結果對象的轉換。一旦實體化後,實體往往非常沉重,我相信你不需要全部屬性。急切的加載是一個選項,但不是一個可行的IMO。 – Kamo

0

使用Serializable()屬性。 試試這個:

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; } 
    } 
} 
0

在什麼終於研究出了禁用ProxyCreationEnabled結束。

所以在我的控制現在我有以下代碼:

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; 
     } 
    } 

這並不意味着我將不得不急於負載,我想用條.include()使用任何的導航性能。

+0

正如我所建議的,您可以通過使用DTO對象將實體轉換爲普通對象來保留延遲加載。 – Kamo

1

請webconfig輸入下面的代碼片段:

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