Er is een kringverwijzing gedetecteerd tijdens het serialiseren van een object van het type ‘SubSonic.Schema .DatabaseColumn’.

Ik probeer een eenvoudige JSON-retour uit te voeren, maar ik heb problemen met het volgende hieronder.

public JsonResult GetEventData()
{
    var data = Event.Find(x => x.ID != 0);
    return Json(data);
}

Ik krijg een HTTP 500 met de uitzondering zoals weergegeven in de titel van deze vraag. Ik heb ook geprobeerd

var data = Event.All().ToList()

Dat gaf hetzelfde probleem.

Is dit een bug of mijn implementatie?


Antwoord 1, autoriteit 100%

Het lijkt erop dat er kringverwijzingen in uw objecthiërarchie zijn die niet worden ondersteund door de JSON-serializer. Heb je alle kolommen nodig? U kunt in de weergave alleen de eigendommen oppikken die u nodig heeft:

return Json(new 
{  
    PropertyINeed1 = data.PropertyINeed1,
    PropertyINeed2 = data.PropertyINeed2
});

Hierdoor wordt uw JSON-object lichter en gemakkelijker te begrijpen. Als u veel eigenschappen heeft, kan AutoMapperworden gebruikt om automatischtoewijzen tussen DTO-objecten en View-objecten.


Antwoord 2, autoriteit 65%

Ik had hetzelfde probleem en opgelost door using Newtonsoft.Json;

var list = JsonConvert.SerializeObject(model,
    Formatting.None,
    new JsonSerializerSettings() {
        ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
});
return Content(list, "application/json");

Antwoord 3, autoriteit 32%

Dit gebeurt in feite omdat de complexe objecten ervoor zorgen dat het resulterende json-object faalt.
En het faalt, want wanneer het object in kaart wordt gebracht, brengt het de kinderen in kaart, die hun ouders in kaart brengen, waardoor een kringverwijzing plaatsvindt. Json zou oneindig veel tijd nodig hebben om het te serialiseren, dus het voorkomt het probleem met de uitzondering.

Entity Framework mapping produceert hetzelfde gedrag, en de oplossing is om alle ongewenste eigenschappen te verwijderen.

Alleen het definitieve antwoord expliciet maken, zou de hele code zijn:

public JsonResult getJson()
{
    DataContext db = new DataContext ();
    return this.Json(
           new {
                Result = (from obj in db.Things select new {Id = obj.Id, Name = obj.Name})
               }
           , JsonRequestBehavior.AllowGet
           );
}

Het kan ook het volgende zijn als u de objecten niet binnen een Result-eigenschap wilt hebben:

public JsonResult getJson()
{
    DataContext db = new DataContext ();
    return this.Json(
           (from obj in db.Things select new {Id = obj.Id, Name = obj.Name})
           , JsonRequestBehavior.AllowGet
           );
}

Antwoord 4, autoriteit 11%

Om alles samen te vatten, zijn er 4 oplossingen hiervoor:

Oplossing 1: schakel ProxyCreation uit voor de DBContext en herstel deze uiteindelijk.

   private DBEntities db = new DBEntities();//dbcontext
    public ActionResult Index()
    {
        bool proxyCreation = db.Configuration.ProxyCreationEnabled;
        try
        {
            //set ProxyCreation to false
            db.Configuration.ProxyCreationEnabled = false;
            var data = db.Products.ToList();
            return Json(data, JsonRequestBehavior.AllowGet);
        }
        catch (Exception ex)
        {
            Response.StatusCode = (int)HttpStatusCode.BadRequest;
            return Json(ex.Message);
        }
        finally
        {
            //restore ProxyCreation to its original state
            db.Configuration.ProxyCreationEnabled = proxyCreation;
        }
    }

Oplossing 2: JsonConvert gebruiken door ReferenceLoopHandling in te stellen om te negeren op de serializer-instellingen.

   //using using Newtonsoft.Json;
    private DBEntities db = new DBEntities();//dbcontext
    public ActionResult Index()
    {
        try
        {
            var data = db.Products.ToList();
            JsonSerializerSettings jss = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
            var result = JsonConvert.SerializeObject(data, Formatting.Indented, jss);
            return Json(result, JsonRequestBehavior.AllowGet);
        }
        catch (Exception ex)
        {
            Response.StatusCode = (int)HttpStatusCode.BadRequest;
            return Json(ex.Message);
        }
    }

De volgende twee oplossingen zijn hetzelfde, maar het gebruik van een model is beter omdat het sterk getypt is.

Oplossing 3: retourneer een model dat alleen de benodigde eigenschappen bevat.

   private DBEntities db = new DBEntities();//dbcontext
    public class ProductModel
    {
        public int Product_ID { get; set;}
        public string Product_Name { get; set;}
        public double Product_Price { get; set;}
    }
    public ActionResult Index()
    {
        try
        {
            var data = db.Products.Select(p => new ProductModel
                                                {
                                                    Product_ID = p.Product_ID,
                                                    Product_Name = p.Product_Name,
                                                    Product_Price = p.Product_Price
                                                }).ToList();
            return Json(data, JsonRequestBehavior.AllowGet);
        }
        catch (Exception ex)
        {
            Response.StatusCode = (int)HttpStatusCode.BadRequest;
            return Json(ex.Message);
        }
    }

Oplossing 4: retourneer een nieuw dynamisch object dat alleen de benodigde eigenschappen bevat.

   private DBEntities db = new DBEntities();//dbcontext
    public ActionResult Index()
    {
        try
        {
            var data = db.Products.Select(p => new
                                                {
                                                    Product_ID = p.Product_ID,
                                                    Product_Name = p.Product_Name,
                                                    Product_Price = p.Product_Price
                                                }).ToList();
            return Json(data, JsonRequestBehavior.AllowGet);
        }
        catch (Exception ex)
        {
            Response.StatusCode = (int)HttpStatusCode.BadRequest;
            return Json(ex.Message);
        }
    }

Antwoord 5, autoriteit 4%

JSON is, net als xml en verschillende andere formaten, een op boom gebaseerde serialisatie-indeling. Het zal niet van je houden als je kringverwijzingen in je objecten hebt, zoals de “boom” zou zijn:

root B => child A => parent B => child A => parent B => ...

Er zijn vaak manieren om navigatie langs een bepaald pad uit te schakelen; met XmlSerializerkunt u bijvoorbeeld de bovenliggende eigenschap markeren als XmlIgnore. Ik weet niet of dit mogelijk is met de json-serializer in kwestie, en ook niet of DatabaseColumngeschikte markeringen heeft (zeeronwaarschijnlijk, omdat het zou moeten verwijzen naar elke serialisatie-API)


Antwoord 6, autoriteit 4%

voeg [JsonIgnore]toe aan virtuals-eigenschappen in uw model.


Antwoord 7, autoriteit 3%

Newtonsoft.Json gebruiken: voeg in uw Global.asax Application_Start-methode deze regel toe:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

Antwoord 8, autoriteit 2%

Het komt door de nieuwe DbContext T4-sjabloon die wordt gebruikt voor het genereren van de EntityFramework-entiteiten. Om het bijhouden van wijzigingen uit te kunnen voeren, gebruikt deze sjabloon het Proxy-patroon, door uw mooie POCO’s ermee in te pakken. Dit veroorzaakt dan de problemen bij het serialiseren met de JavaScriptSerializer.

Dus dan zijn de 2 oplossingen:

  1. Ofwel je serialiseert en retourneert de eigenschappen die je nodig hebt op de client
  2. U kunt het automatisch genereren van proxy’s uitschakelen door dit in te stellen in de configuratie van de context

    context.Configuration.ProxyCreationEnabled = false;

Zeer goed uitgelegd in het onderstaande artikel.

http://juristr.com/blog/2011/08/javascriptserializer -circulaire-referentie/


Antwoord 9, autoriteit 2%

De gegeven antwoorden zijn goed, maar ik denk dat ze kunnen worden verbeterd door een ‘architectonisch’ perspectief toe te voegen.

Onderzoek

MVC's Controller.Json-functie doet het werk, maar is in dit geval erg slecht in het geven van een relevante fout. Door Newtonsoft.Json.JsonConvert.SerializeObjectte gebruiken, geeft de fout precies aan wat de eigenschap is die de kringverwijzing activeert. Dit is vooral handig bij het serialiseren van complexere objecthiërarchieën.

Goede architectuur

Men moet nooit proberen datamodellen te serialiseren (bijv. EF-modellen), aangezien de navigatie-eigenschappen van ORM de weg naar de ondergang zijn als het gaat om serialisatie. De gegevensstroom moet als volgt zijn:

Database -> data models -> service models -> JSON string 

Servicemodellen kunnen worden verkregen uit gegevensmodellen met behulp van automatische mappers (bijv. Automapper). Hoewel dit geen gebrek aan kringverwijzingen garandeert, zou een goed ontwerp het moeten doen: servicemodellen moeten precies bevatten wat de serviceconsument nodig heeft (d.w.z. de eigenschappen).

In die zeldzame gevallen, wanneer de klant een hiërarchie aanvraagt ​​met hetzelfde objecttype op verschillende niveaus, kan de service een lineaire structuur creëren met een parent->child-relatie (met alleen identifiers, geen referenties).

Moderne applicaties hebben de neiging om complexe datastructuren niet in één keer te laden en servicemodellen moeten slank zijn. Bijv.:

  1. toegang tot een gebeurtenis – alleen kopgegevens (identifier, naam, datum etc.) worden geladen -> servicemodel (JSON) dat alleen headergegevens bevat
  2. lijst met beheerde deelnemers – open een pop-up en laad de lijst lui -> servicemodel (JSON) dat alleen de lijst met deelnemers bevat

Antwoord 10, autoriteit 2%

Vermijd het rechtstreeks converteren van het tabelobject. Als er relaties tussen andere tabellen zijn ingesteld, kan deze fout optreden.
In plaats daarvan kunt u een modelklasse maken, waarden toewijzen aan het klasseobject en het vervolgens serialiseren.


Antwoord 11

Ik gebruik de oplossing, omdat Knockout wordt gebruikt in MVC5-weergaven.

In actie

return Json(ModelHelper.GetJsonModel<Core_User>(viewModel));

functie

  public static TEntity GetJsonModel<TEntity>(TEntity Entity) where TEntity : class
    {
        TEntity Entity_ = Activator.CreateInstance(typeof(TEntity)) as TEntity;
        foreach (var item in Entity.GetType().GetProperties())
        {
            if (item.PropertyType.ToString().IndexOf("Generic.ICollection") == -1 && item.PropertyType.ToString().IndexOf("SaymenCore.DAL.") == -1)
                item.SetValue(Entity_, Entity.GetPropValue(item.Name));
        }
        return Entity_;  
    }

Antwoord 12

U kunt de eigenschappen opmerken die de kringverwijzing veroorzaken. Dan kun je iets doen als:

private Object DeCircular(Object object)
{
   // Set properties that cause the circular reference to null
   return object
}

Antwoord 13

//first: Create a class as your view model
public class EventViewModel 
{
 public int Id{get;set}
 public string Property1{get;set;}
 public string Property2{get;set;}
}
//then from your method
[HttpGet]
public async Task<ActionResult> GetEvent()
{
 var events = await db.Event.Find(x => x.ID != 0);
 List<EventViewModel> model = events.Select(event => new EventViewModel(){
 Id = event.Id,
 Property1 = event.Property1,
 Property1 = event.Property2
}).ToList();
 return Json(new{ data = model }, JsonRequestBehavior.AllowGet);
}

Antwoord 14

Een eenvoudiger alternatief om dit probleem op te lossen is om een ​​tekenreeks te retourneren en die tekenreeks te formatteren naar json met JavaScriptSerializer.

public string GetEntityInJson()
{
   JavaScriptSerializer j = new JavaScriptSerializer();
   var entityList = dataContext.Entitites.Select(x => new { ID = x.ID, AnotherAttribute = x.AnotherAttribute });
   return j.Serialize(entityList );
}

Het is belangrijk het gedeelte “Selecteren”, dat de eigenschappen kiest die u in uw weergave wilt hebben. Sommige objecten hebben een verwijzing naar de ouder. Als u de attributen niet kiest, kan de kringverwijzing verschijnen, als u alleen de tabellen als geheel neemt.

Doe dit niet:

public string GetEntityInJson()
{
   JavaScriptSerializer j = new JavaScriptSerializer();
   var entityList = dataContext.Entitites.toList();
   return j.Serialize(entityList );
}

Doe dit in plaats daarvan als je niet de hele tafel wilt:

public string GetEntityInJson()
{
   JavaScriptSerializer j = new JavaScriptSerializer();
   var entityList = dataContext.Entitites.Select(x => new { ID = x.ID, AnotherAttribute = x.AnotherAttribute });
   return j.Serialize(entityList );
}

Dit helpt bij het weergeven van een weergave met minder gegevens, alleen met de kenmerken die u nodig hebt, en zorgt ervoor dat uw internet sneller werkt.

Other episodes