本博客为作者日常工作遇到的一些问题集合,希望能给热爱编程的初学者一些知识。
基于在应用EF实体类,如果存在导航属性,则return Json(List<Entity> list,JsonRequestBehavior.AllowGet)时会遇到无限循环导致报错的问题,所以希望有办法解决此问题。
解决思路1:
1.新增多一个EF模板,把其导航属性去除。
在.tt模板中,把类名加Model,与原来的类名区分开来。
<#=codeStringGenerator.EntityClassOpening(entity)+"Model"#>
<# foreach (var navigationProperty in navigationProperties) { #> <#=codeStringGenerator.NavigationProperty(navigationProperty)#> <# } } #>
2.利用一个方法把List<Entity>批量转换成List<EntityModel>。
public class Mapper<T,K> { /// <summary> /// 把List<T>转换成List<K> /// </summary> /// <param name="listT"></param> /// <param name="model">默认new Model()</param> /// <returns></returns> public static List<K> MapObjectList(List<T> listT, K model) { BinaryFormatter bf = new BinaryFormatter(); MemoryStream ms = new MemoryStream(); bf.Serialize(ms, model); //复制到流中 List<K> listK = new List<K>(); foreach (T t in listT) { ms.Position = 0; K k = (K)(bf.Deserialize(ms)); ObjectMapperManager.DefaultInstance.GetMapper<T, K>().Map(t, k); listK.Add(k); } return listK; }
3.可用return Json(List<EntityModel> list,JsonRequestBehavior.AllowGet)
这样把其导航属性去掉,前台就不会出现无线循环的报错了。
如果哪位大神有更好的解决办法,请赐教。
EmitMapper.ObjectMapperManager 可以在nuget里面找到,挺好用的一个类,是用来把EntityA转换成EntityB,把两个实体相同属性的名称
对应赋值。
但是,这样做效率似乎不高,而且还比较麻烦。于是再找找有没有更便捷的方法,毕竟每次都这样又装箱又拆箱,性能损耗也是不少。于是有了解决思路2
解决思路2:
直接利用方法去除类中的导航属性!!
写一个MyJsonResult类
public class JsonNetResult : JsonResult { public JsonSerializerSettings Settings { get; private set; } public JsonNetResult() { Settings = new JsonSerializerSettings { //这句是解决问题的关键,也就是json.net官方给出的解决配置选项. ReferenceLoopHandling = ReferenceLoopHandling.Ignore }; } public override void ExecuteResult(ControllerContext context) { if (context == null) throw new ArgumentNullException("context"); if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet && string.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) throw new InvalidOperationException("JSON GET is not allowed"); HttpResponseBase response = context.HttpContext.Response; response.ContentType = string.IsNullOrEmpty(this.ContentType) ? "application/json" : this.ContentType; if (this.ContentEncoding != null) response.ContentEncoding = this.ContentEncoding; if (this.Data == null) return; var scriptSerializer = JsonSerializer.Create(this.Settings); using (var sw = new StringWriter()) { scriptSerializer.Serialize(sw, this.Data); response.Write(sw.ToString()); } } }
然后,在BaseController里重写Json方法
public class BaseController : Controller { protected override JsonResult Json(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior) { return new JsonNetResult { Data = data, ContentType = contentType, ContentEncoding = contentEncoding, JsonRequestBehavior = behavior }; } }
原文:http://www.cnblogs.com/gmxq/p/4921974.html