Ich verwende Entity Framework und habe ein Problem damit, übergeordnete und untergeordnete Daten in den Browser zu übertragen. Hier sind meine Klassen:
public class Question
{
public int QuestionId { get; set; }
public string Title { get; set; }
public virtual ICollection<Answer> Answers { get; set; }
}
public class Answer
{
public int AnswerId { get; set; }
public string Text { get; set; }
public int QuestionId { get; set; }
public virtual Question Question { get; set; }
}
Ich verwende den folgenden Code, um die Frage- und Antwortdaten zurückzugeben:
public IList<Question> GetQuestions(int subTopicId, int questionStatusId)
{
var questions = _questionsRepository.GetAll()
.Where(a => a.SubTopicId == subTopicId &&
(questionStatusId == 99 ||
a.QuestionStatusId == questionStatusId))
.Include(a => a.Answers)
.ToList();
return questions;
}
Auf der C # -Seite scheint dies zu funktionieren, aber ich stelle fest, dass die Antwortobjekte Verweise auf die Frage haben. Wenn ich die WebAPI verwende, um die Daten an den Browser zu senden, wird folgende Meldung angezeigt:
Der Typ 'ObjectContent`1' konnte den Antworttext für den Inhaltstyp 'application / json nicht serialisieren. Zeichensatz = utf-8 '.
Selbstreferenzierende Schleife für Eigenschaft 'Frage' mit Typ 'Models.Core.Question' erkannt.
Liegt das daran, dass die Frage Antworten enthält und die Antworten einen Verweis auf die Frage haben? Alle Orte, an denen ich gesucht habe, schlagen vor, einen Verweis auf die Eltern im Kind zu haben, sodass ich nicht sicher bin, was ich tun soll. Kann mir jemand einen Rat geben.
quelle
Antworten:
Ja. Es kann nicht serialisiert werden.
BEARBEITEN: Siehe Tallmaris 'Antwort und OttOs Kommentar, da er einfacher ist und global eingestellt werden kann.
Alte Antwort:
Projizieren Sie das EF-Objekt
Question
auf Ihr eigenes Intermediate- oder DataTransferObject. Dieses Dto kann dann erfolgreich serialisiert werden.public class QuestionDto { public QuestionDto() { this.Answers = new List<Answer>(); } public int QuestionId { get; set; } ... ... public string Title { get; set; } public List<Answer> Answers { get; set; } }
Etwas wie:
public IList<QuestionDto> GetQuestions(int subTopicId, int questionStatusId) { var questions = _questionsRepository.GetAll() .Where(a => a.SubTopicId == subTopicId && (questionStatusId == 99 || a.QuestionStatusId == questionStatusId)) .Include(a => a.Answers) .ToList(); var dto = questions.Select(x => new QuestionDto { Title = x.Title ... } ); return dto; }
quelle
Sie können dies auch in Ihrem
Application_Start()
:Es sollte Ihr Problem beheben, ohne viele Reifen zu durchlaufen.
BEARBEITEN : Verwenden Sie gemäß dem folgenden Kommentar von OttO
ReferenceLoopHandling.Ignore
stattdessen : .quelle
Create()
Methode erstellen , die eine Einstellung als Parameter akzeptiert. Docs: newtonsoft.com/json/help/html/…Wenn Sie OWIN verwenden, denken Sie daran, dass Sie keine GlobalSettings mehr für Sie haben! Sie müssen dieselbe Einstellung in einem HttpConfiguration-Objekt ändern, das an die IAppBuilder UseWebApi-Funktion (oder an die Serviceplattform, auf der Sie sich befinden) übergeben wird.
Würde ungefähr so aussehen.
public void Configuration(IAppBuilder app) { //auth config, service registration, etc var config = new HttpConfiguration(); config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; //other config settings, dependency injection/resolver settings, etc app.UseWebApi(config); }
quelle
In ASP.NET Core lautet der Fix wie folgt:
quelle
Wenn Sie DNX / MVC 6 / ASP.NET vNext verwenden,
HttpConfiguration
fehlt sogar bla . Sie müssen Formatierer konfigurieren, indem Sie die folgenden Codes in IhrerStartup.cs
Datei verwenden.public void ConfigureServices(IServiceCollection services) { services.AddMvc().Configure<MvcOptions>(option => { //Clear all existing output formatters option.OutputFormatters.Clear(); var jsonOutputFormatter = new JsonOutputFormatter(); //Set ReferenceLoopHandling jsonOutputFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; //Insert above jsonOutputFormatter as the first formatter, you can insert other formatters. option.OutputFormatters.Insert(0, jsonOutputFormatter); }); }
quelle
ASP.NET Core-Web-API (.NET Core 2.0):
// Startup.cs public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.Configure<MvcJsonOptions>(config => { config.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; }); }
quelle
Verwenden Sie diese:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore
hat bei mir nicht funktioniert. Stattdessen habe ich eine neue, vereinfachte Version meiner Modellklasse erstellt, um sie zu testen, und das hat gut funktioniert. Dieser Artikel befasst sich mit einigen Problemen, die ich in meinem Modell hatte und die für EF hervorragend funktionierten, aber nicht serialisierbar waren:
http://www.asp.net/web-api/overview/data/using-web-api-with-entity-framework/part-4
quelle
ReferenceLoopHandling.Ignore hat bei mir nicht funktioniert. Die einzige Möglichkeit, dies zu umgehen, bestand darin, die Links zu den Eltern, die ich nicht wollte, per Code zu entfernen und die Links beizubehalten, die ich getan hatte.
parent.Child.Parent = null;
quelle
Für eine neue Asp.Net-Webanwendung mit .Net Framework 4.5:
Web-API: Gehe zu App_Start -> WebApiConfig.cs:
Sollte ungefähr so aussehen:
public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API configuration and services // Configure Web API to use only bearer token authentication. config.SuppressDefaultHostAuthentication(); config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType)); // ReferenceLoopHandling.Ignore will solve the Self referencing loop detected error config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; //Will serve json as default instead of XML config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html")); // Web API routes config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } }
quelle
Als Teil von ASP.NET Core 3.0 hat das Team Json.NET standardmäßig nicht mehr aufgenommen. Weitere Informationen hierzu finden Sie im Allgemeinen unter [Einschließlich Json.Net bis Netcore 3.x] [1] https://github.com/aspnet/Announcements/issues/325
Ein Fehler kann durch die Verwendung von Lazyloading verursacht werden: services.AddDbContext (options => options.UseLazyLoadingProxies () ... oder db.Configuration.LazyLoadingEnabled = true;
Fix: Hinzufügen zu startup.cs
quelle
Aufgrund des verzögerten Ladens wird dieser Fehler angezeigt. Daher ist mein Vorschlag, den virtuellen Schlüssel aus der Eigenschaft zu entfernen. Wenn Sie mit API arbeiten, ist das verzögerte Laden nicht gut für Ihren API-Zustand.
Sie müssen Ihrer Konfigurationsdatei keine zusätzliche Zeile hinzufügen.
public class Question { public int QuestionId { get; set; } public string Title { get; set; } public ICollection<Answer> Answers { get; set; } } public class Answer { public int AnswerId { get; set; } public string Text { get; set; } public int QuestionId { get; set; } public Question Question { get; set; } }
quelle
Ich stellte fest, dass dieser Fehler verursacht wurde, als ich ein edmx (XML-Datei, die ein konzeptionelles Modell definiert) einer vorhandenen Datenbank generierte und Navigationseigenschaften sowohl für die übergeordnete als auch für die untergeordnete Tabelle hatte. Ich habe alle Navigationslinks zu den übergeordneten Objekten gelöscht, da ich nur zu untergeordneten Objekten navigieren wollte, und das Problem wurde behoben.
quelle
Entitäten db = neue Entitäten ()
db.Configuration.ProxyCreationEnabled = false;
db.Configuration.LazyLoadingEnabled = false;
quelle
Sie können dynamisch eine neue untergeordnete Sammlung erstellen, um dieses Problem einfach zu umgehen.
public IList<Question> GetQuestions(int subTopicId, int questionStatusId) { var questions = _questionsRepository.GetAll() .Where(a => a.SubTopicId == subTopicId && (questionStatusId == 99 || a.QuestionStatusId == questionStatusId)) .Include(a => a.Answers).Select(b=> new { b.QuestionId, b.Title Answers = b.Answers.Select(c=> new { c.AnswerId, c.Text, c.QuestionId })) .ToList(); return questions; }
quelle
Keine der Konfigurationen in den obigen Antworten hat in ASP.NET Core 2.2 für mich funktioniert.
Ich musste die
JsonIgnore
Attribute in meinen virtuellen Navigationseigenschaften hinzufügen .public class Question { public int QuestionId { get; set; } public string Title { get; set; } [JsonIgnore] public virtual ICollection<Answer> Answers { get; set; } }
quelle