好的,我收到了这个错误:
在序列化“System.Data.Entity.DynamicProxies.Asset_AED71699FAD007BF6F823A5F022DB9888F62EBBD9E422BBB11D7A191CD784288”类型的对象时检测到循环引用。
我明白这意味着什么。我的代码是从VisualStudioTools生成的,它生成了所有具有虚拟导航属性的POCO并映射了关系。 我很满意,我想要延迟加载。
以下是我的用户类的示例:
public partial class User : IdentityUser
{
public User()
{
this.Assets = new List<Asset>();
this.Categories = new List<Category>();
this.Collections = new List<Collection>();
this.Comments = new List<Comment>();
this.LocalIntegrations = new List<LocalIntegration>();
this.Pages = new List<Page>();
this.Ratings = new List<Rating>();
this.Themes = new List<Theme>();
this.ForbiddenCategories = new List<Category>();
this.ForbiddenPages = new List<Page>();
}
public string CompanyId { get; set; }
public string CreatedById { get; set; }
public string ModifiedById { get; set; }
public System.DateTime DateCreated { get; set; }
public Nullable<System.DateTime> DateModified { get; set; }
public System.DateTime LastLoginDate { get; set; }
public string Title { get; set; }
public string Forename { get; set; }
public string Surname { get; set; }
public string Email { get; set; }
public string JobTitle { get; set; }
public string Telephone { get; set; }
public string Mobile { get; set; }
public string Photo { get; set; }
public string LinkedIn { get; set; }
public string Twitter { get; set; }
public string Facebook { get; set; }
public string Google { get; set; }
public string Bio { get; set; }
public string CompanyName { get; set; }
public string CredentialId { get; set; }
public bool IsLockedOut { get; set; }
public bool IsApproved { get; set; }
public bool CanEditOwn { get; set; }
public bool CanEdit { get; set; }
public bool CanDownload { get; set; }
public bool RequiresApproval { get; set; }
public bool CanApprove { get; set; }
public bool CanSync { get; set; }
public bool AgreedTerms { get; set; }
public bool Deleted { get; set; }
public virtual Company Company { get; set; }
public virtual User CreatedBy { get; set; }
public virtual User ModifiedBy { get; set; }
public virtual ICollection<Asset> Assets { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public virtual ICollection<Collection> Collections { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
public virtual ICollection<LocalIntegration> LocalIntegrations { get; set; }
public virtual ICollection<Page> Pages { get; set; }
public virtual ICollection<Rating> Ratings { get; set; }
public virtual ICollection<Theme> Themes { get; set; }
public virtual ICollection<Group> MemberOf { get; set; }
public virtual ICollection<Category> ForbiddenCategories { get; set; }
public virtual ICollection<Page> ForbiddenPages { get; set; }
}
我的小组课程看起来像这样:
public partial class Group
{
public Group()
{
this.ForbiddenCategories = new List<Category>();
this.ForbiddenPages = new List<Page>();
this.Members = new List<User>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string CompanyId { get; set; }
public bool Preset { get; set; }
public Nullable<bool> CanEdit { get; set; }
public Nullable<bool> CanEditOwn { get; set; }
public Nullable<bool> CanDownload { get; set; }
public Nullable<bool> RequiresApproval { get; set; }
public Nullable<bool> CanApprove { get; set; }
public System.DateTime DateCreated { get; set; }
public bool CanSync { get; set; }
public Nullable<System.DateTime> DateModified { get; set; }
public string CreatedById { get; set; }
public string ModifiedById { get; set; }
public bool Deleted { get; set; }
public virtual Company Company { get; set; }
public virtual User CreatedBy { get; set; }
public virtual User ModifiedBy { get; set; }
public virtual ICollection<Category> ForbiddenCategories { get; set; }
public virtual ICollection<Page> ForbiddenPages { get; set; }
public virtual ICollection<User> Members { get; set; }
}
我读到为了停止循环引用,你可以这样做:
public async Task<JsonResult> Get()
{
try
{
using (var service = new UserService(new CompanyService()))
{
var u = from user in await service.GetAll()
select new
{
Id = user.Id,
UserName = user.UserName,
Email = user.Email,
IsApproved = user.IsApproved,
IsLockedOut = user.IsLockedOut,
MemberOf = user.MemberOf
};
return new JsonResult { Data = new { success = true, users = u } }; // Return our users
}
}
catch (Exception ex)
{
return new JsonResult { Data = new { success = false, error = ex.Message } };
}
}
但由于 MemberOf 而退回用户时失败。 循环引用是用户,其中集合,每个资产都有用户创建它。
有没有办法让它只在第一个POCO(在这种情况下是用户类)上进行延迟加载,这样它只会加载MemberOf,Assets等,但不会加载其余的(即不是用户&gt;资产&gt;用户)??
更新1
evanmcdonnal建议它可能是 JsonResult 而不是我的POCO类的问题,所以我决定看一下是否有办法验证它。 基本上我创建了一个继承自 JsonResult 的 JsonNetResult 类,并且我覆盖了 ExecuteResult 。这就是它的样子:public class JsonNetResult : JsonResult
{
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
var response = context.HttpContext.Response;
response.ContentType = !String.IsNullOrEmpty(ContentType) ? ContentType : "application/json";
if (ContentEncoding != null)
response.ContentEncoding = ContentEncoding;
if (Data == null)
return;
// If you need special handling, you can call another form of SerializeObject below
var serializedObject = JsonConvert.SerializeObject(Data, Formatting.Indented);
response.Write(serializedObject);
}
}
所以我的方法现在看起来像这样:
public async Task<JsonNetResult> Get()
{
try
{
using (var service = new UserService(new CompanyService()))
{
var u = from user in await service.GetAll()
select new
{
Id = user.Id,
UserName = user.UserName,
Email = user.Email,
IsApproved = user.IsApproved,
IsLockedOut = user.IsLockedOut,
MemberOf = user.MemberOf
};
return new JsonNetResult { Data = new { success = true, users = u } }; // Return our users
}
}
catch (Exception ex)
{
return new JsonNetResult { Data = new { success = false, error = ex.Message } };
}
}
当我运行它时,我得到了与以前相同的错误,但它显示了更多细节。它实际上说明了这一点:
Newtonsoft.Json.dll中发生了'Newtonsoft.Json.JsonSerializationException'类型的异常,但未在用户代码中处理
附加信息:使用类型'System.Data.Entity.DynamicProxies.Asset_AED71699FAD007BF6F823A5F022DB9888F62EBBD9E422BBB11D7A191CD784288'检测到自引用循环。路径'users [0] .MemberOf [0] .Company.Assets [0] .Categories [0] .Assets'。
现在我要查看是否可以更改递归限制:(
答案 0 :(得分:0)
您可以尝试将[DataContract(IsReference = true)]添加到您的班级。这将使用引用ID序列化您的对象,并应解决循环引用问题。
答案 1 :(得分:0)
根据您的更新,我将假设RecursionLimit
的当前值是问题所在。该属性的文档相对稀疏,但可以在这里找到它们http://msdn.microsoft.com/en-us/library/system.web.mvc.jsonresult.recursionlimit(v=vs.118).aspx
我相信您可以通过使用以下代码行替换当前的返回行来解决此问题;
JsonResult retVal = new JsonResult();
retVal.RecursionLimit = 1000; //maybe parameteraize this?
reVal.Data = = new { success = true, users = u };
return retVal;
编辑:更新后我知道如何轻松解决问题,因为JsonConvert.SerializeObject
现在抛出了异常,我之前已经解决了这个问题:)
根据您的更新,您可以通过更改ExecuteResult
中的一些代码轻松解决此问题(此选项我更有信心,因为我实际在当前项目中实现了它,我个人没有使用{{ 1}}类和我以前的建议只是我利用我对json.NET的一般知识)。您可以调用JsonResult
的重载,例如下面的示例,当您有循环引用时它将抛出;
SerializeObject
string json = JsonConvert.SerializeObject(YourInstanceToSerialize, Formatting.Indented,
new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Serialize });
的可用值可在此处找到; http://james.newtonking.com/json/help/index.html?topic=html/T_Newtonsoft_Json_ReferenceLoopHandling.htm我认为默认值是0,这就是你的代码抛出的原因。既然您已经更新了这些更改,我想我会建议使用第二种方法(我至少知道它会起作用),但也可以尝试第一种方法。
答案 2 :(得分:0)
我发现关闭这些查询的延迟加载工作。只需确保您的查询通过&#34; include&#34;选择所需的全部内容。如果需要的话。 然后在查询之前:
efContext.Configuration.LazyLoadingEnabled = false;