【问题标题】:Unloaded "eager-loaded" properties causing issues when returning json'd data返回 json 数据时,卸载的“急切加载”属性会导致问题
【发布时间】:2014-04-15 22:03:58
【问题描述】:

希望标题有意义,我会尽力描述我的问题。

我目前正在开发一个 ASP.NET Web API。在我的“公司”控制器中,我有一个 GetCompany() 操作。

    /// <summary>
    /// Gets the 'Authorization-Token' request header and finds the company with the
    /// matching decrypted token from the database, returns it; if null, returns 404
    /// </summary>
    /// <returns>Matching company for token passed in request or 404 if null</returns>
    [HttpGet][ResponseType(typeof(Company))]
    [Route("api/company/")]
    public HttpResponseMessage GetCompany() {
        string token = Request.Headers.GetValues("Authorization-Token").First();

        ICollection<Company> companies;
        Company c;
        using (BaseRepository r = new BaseRepository()) {
            companies = r.Get<Company>(null, null, null);
            c = companies.Where(cm => RSA.Decrypt(cm.Token) == token).FirstOrDefault<Company>();
        }
        if (c == null)
            return Request.CreateResponse(HttpStatusCode.NotFound, c);

        return Request.CreateResponse(HttpStatusCode.OK, c);
    }

这找到并返回它就好了,但是当我测试这个时,我看到的响应是

{
    "Message": "An error has occurred.",
    "ExceptionMessage": "The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.",
    "ExceptionType": "System.InvalidOperationException",
    "StackTrace": null,
    "InnerException": {
        "Message": "An error has occurred.",
        "ExceptionMessage": "Error getting value from 'Locations' on 'System.Data.Entity.DynamicProxies.Company_40636FF93138F09772BEA689D3A3D3AB7DBB41AFF7FE3D0BEFF55FC7C1D10E0F'.",
        "ExceptionType": "Newtonsoft.Json.JsonSerializationException",
        "StackTrace": "   at Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target)\r\n   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer, Object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, JsonContract& memberContract, Object& memberValue)\r\n   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)\r\n   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)\r\n   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)\r\n   at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)\r\n   at Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter, Object value)\r\n   at System.Net.Http.Formatting.JsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content)\r\n   at System.Net.Http.Formatting.JsonMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()\r\n   at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__14.MoveNext()",
        "InnerException": {
            "Message": "An error has occurred.",
            "ExceptionMessage": "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.",
            "ExceptionType": "System.ObjectDisposedException",
            "StackTrace": "   at System.Data.Entity.Core.Objects.ObjectContext.get_Connection()\r\n   at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)\r\n   at System.Data.Entity.Core.Objects.ObjectQuery`1.Execute(MergeOption mergeOption)\r\n   at System.Data.Entity.Core.Objects.DataClasses.EntityCollection`1.Load(List`1 collection, MergeOption mergeOption)\r\n   at System.Data.Entity.Core.Objects.DataClasses.EntityCollection`1.Load(MergeOption mergeOption)\r\n   at System.Data.Entity.Core.Objects.DataClasses.RelatedEnd.Load()\r\n   at System.Data.Entity.Core.Objects.DataClasses.RelatedEnd.DeferredLoad()\r\n   at System.Data.Entity.Core.Objects.Internal.LazyLoadBehavior.LoadProperty[TItem](TItem propertyValue, String relationshipName, String targetRoleName, Boolean mustBeNull, Object wrapperObject)\r\n   at System.Data.Entity.Core.Objects.Internal.LazyLoadBehavior.<>c__DisplayClass7`2.<GetInterceptorDelegate>b__1(TProxy proxy, TItem item)\r\n   at System.Data.Entity.DynamicProxies.Company_40636FF93138F09772BEA689D3A3D3AB7DBB41AFF7FE3D0BEFF55FC7C1D10E0F.get_Locations()\r\n   at GetLocations(Object )\r\n   at Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target)"
        }
    }
}

我了解问题在于我的属性是预先加载的,并且从未加载过。我可以告诉它很容易地在我的Company 对象中加载我的导航属性。我这样做时遇到的问题是,上面提到的导航属性中的复杂对象也是空的,我不能那么容易地急切地加载它们;我也不想。所以它试图加载整个“对象树”,因为没有更好的表达方式(我能想到)。

所以我的问题是,解决这个问题的最佳方法是什么?

【问题讨论】:

    标签: c# json eager-loading asp.net-web-api2


    【解决方案1】:

    代理导致序列化程序尝试访问导航属性,这些属性在上下文已被释放后不再可用。

    当您查询将被序列化的对象时,尝试从您的上下文中删除代理和预加载

     context.Configuration.ProxyCreationEnabled = false;
     context.Configuration.LazyLoadingEnabled = false;
    

    【讨论】:

    • 谢谢!目前开车回家,但我会尽快检查!
    • 像一个魅力一样工作,之前在 OnModelCreating 中通过说 base.Configuration.* 来执行此操作,但将其移动到我的上下文的构造函数解决了它。
    • 我只是想对此进行扩展,有时您不想更改为急切加载,因为如果您在其他地方使用(重)对象可能会对性能产生影响。如果是这种情况,请考虑将惰性对象包装到另一个对象(例如 ViewModel)中,并仅评估您需要的属性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    • 1970-01-01
    相关资源
    最近更新 更多