EF在轉換成JsonResult時遇到無限循環的解決辦法

本博客爲做者平常工做遇到的一些問題集合,但願能給熱愛編程的初學者一些知識。編程

基於在應用EF實體類,若是存在導航屬性,則return Json(List<Entity> list,JsonRequestBehavior.AllowGet)時會遇到無限循環致使報錯的問題,因此但願有辦法解決此問題。json

解決思路1:app

1.新增多一個EF模板,把其導航屬性去除。ide

在.tt模板中,把類名加Model,與原來的類名區分開來。oop

<#=codeStringGenerator.EntityClassOpening(entity)+"Model"#>
T4模板代碼
<#
        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;
        }
View Code

 

3.可用return Json(List<EntityModel> list,JsonRequestBehavior.AllowGet)學習

這樣把其導航屬性去掉,前臺就不會出現無線循環的報錯了。this

 EmitMapper.ObjectMapperManager 能夠在nuget裏面找到,挺好用的一個類,是用來把EntityA轉換成EntityB,把兩個實體相同屬性的名稱spa

對應賦值。.net

  可是,這樣作效率彷佛不高,並且還比較麻煩。因而再找找有沒有更便捷的方法,畢竟每次都這樣又裝箱又拆箱,性能損耗也是很多。因而有了解決思路2

 

解決思路2:

 直接利用方法去除類中的導航屬性!!

寫一個MyJsonResult類

public class MyJsonResult : JsonResult 
    {
        public JsonSerializerSettings Settings { get; private set; } 

        public MyJsonResult()
        { 
            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 MyJsonResult 
            { 
                Data = data, 
                ContentType = contentType, 
                ContentEncoding = contentEncoding, 
                JsonRequestBehavior = behavior }; 
        }

    }

  最後只需在Controller裏繼承BaseController就好了。很是方便!並且沒有轉換效率的問題。解決思路2是推薦的辦法。固然也在解決思路1中學習到了很多的知識。
若是哪位大神有更好的解決辦法,請賜教。
相關文章
相關標籤/搜索