2010-05-26 6 views
8

OK, ich möchte sicherstellen, dass ich meine Situation und alles, was ich gründlich ausprobiert habe abdecken. Ich bin mir ziemlich sicher, was ich brauche/will, aber ich habe nicht die perfekte Kombination für den Erfolg gefunden.EF4 POCO WCF Serialisierung Probleme (keine Lazy Loading, Proxy/kein Proxy, Zirkelverweise, etc.)

Ich Verwendung Entity Framework 4 RTM und seine POCO Unterstützung. Ich suche nach einer Entität (Config), die eine Viele-zu-Viele-Beziehung mit einer anderen Entität (App) enthält. Ich wende aus lazy loading und deaktivieren Proxy-Erstellung für den Kontext und laden Sie explizit die Navigationseigenschaft (entweder durch .Include() oder .LoadProperty()). Wenn jedoch die Navigationseigenschaft geladen ist (dh Apps werden für eine bestimmte Konfiguration geladen), enthalten die geladenen App-Objekte bereits Verweise auf die Configs, die in den Speicher geladen wurden. Dies erzeugt eine Kreisreferenz.

Jetzt weiß ich, dass der DataContractSerializer, den WCF verwendet, zirkuläre Referenzen verarbeiten kann, indem er den Parameter preserveObjectReferences auf true setzt. Ich habe das mit ein paar verschiedenen Attribution-Implementierungen versucht, die ich online gefunden habe. Es ist erforderlich, um zu verhindern, dass der Fehler "das Objektdiagramm enthält Zirkelbezüge und kann nicht serialisiert werden". Es verhindert jedoch nicht die Serialisierung des gesamten Graphen zwischen Config und App.

Wenn ich es über WcfTestClient.exe aufrufen, bekomme ich eine stackoverflow (ha!) Ausnahme vom Client und ich bin abgespritzt. Ich erhalte unterschiedliche Ergebnisse aus verschiedenen Aufrufumgebungen (C# Unit Test mit einem lokalen Verweis auf den Webdienst scheint in Ordnung zu sein, obwohl ich immer noch endlos zwischen Configs und Apps hin- und herbohren kann, aber den Aufruf aus einer Coldfusion-Umgebung gibt nur die erste Config zurück in der Liste und Fehler in den anderen.) Mein Hauptziel ist es, eine serialisierte Darstellung des Graphen habe ich explizit von EF laden (dh: Liste der Configs, jeweils mit ihren Apps, aber keine App zurück zu Config Navigation.)

HINWEIS: Ich habe auch versucht, die ProxyDataContractResolver-Technik und halten Sie die Proxy-Erstellung aktiviert aus meinem Kontext. Dies führt dazu, dass man sich über unbekannte Arten beklagen muss. Ich habe gelesen, dass der ProxyDataContractResolver in Beta2 nicht vollständig funktioniert hat, aber in RTM funktionieren sollte.

Für einige Referenz, hier ungefähr, wie ich die Daten im Dienst bin Abfrage:

var repo = BootStrapper.AppCtx["AppMeta.ConfigRepository"] as IRepository<Config>; 
repo.DisableLazyLoading(); 
repo.DisableProxyCreation(); 

//var temp2 = repo.Include(cfg => cfg.Apps).Where(cfg => cfg.Environment.Equals(environment)).ToArray(); 
var temp2 = repo.FindAll(cfg => cfg.Environment.Equals(environment)).ToArray(); 
foreach (var cfg in temp2) 
{ 
    repo.LoadProperty(cfg, c => c.Apps); 
} 

return temp2; 

Ich glaube, der Kern meines Problems ist, wenn Navigationseigenschaften für POCO Objekte von Entity Framework 4 Laden auf, Es enthält bereits Navigationseigenschaften für Objekte, die sich bereits im Speicher befinden. Dies wiederum verschlingt die WCF-Serialisierung, trotz aller Anstrengungen, um zirkuläre Referenzen richtig zu handhaben.

Ich weiß, es sind viele Informationen, aber es steht mir wirklich im Weg, mit EF4/POCO in unserem System weiterzumachen. Ich habe mehrere Artikel und Blogs gefunden, die diese Themen betreffen, aber für mein Leben kann ich dieses Problem nicht lösen. Fühlen Sie sich frei, einfach Fragen zu stellen und helfen Sie mir, diese Situation zu verstehen.

PS: Aus Gründen des Seins gründlich, ich die WCF-Dienste am Injektion des HEAD-Build von Spring.NET für das Update auf Spring.ServiceModel.Activation.ServiceHostFactory verwenden. Ich glaube jedoch nicht, dass dies die Ursache des Problems ist.

EDIT: Die Klasse ProxyDataContractResolver funktioniert ordnungsgemäß, wenn ich nicht die Zirkelverweise habe. (Das heißt, ich setze den Setzer von App.Configs als privat, was die Serialisierung der Eigenschaft verhindert.) Es explodiert, wie es scheint, wenn es Configs über das App-Objekt trifft - sie scheinen nicht als das erkannt zu werden gleicher Typ wie die Top-Level-Configs.

EDIT2: Es scheint, dass entweder EF oder WCF nicht erkennt, dass die Entitäten tatsächlich gleich sind. Beispiel: 'Config' ist identisch mit einem bestimmten 'Config.Apps [x] .Configs [y]'. Die Entitätsschlüssel sind in der CSDL für jedes Modell ordnungsgemäß festgelegt, und ich habe die Funktion Equals() überschrieben, um Entitäten basierend auf ihrer Id-Eigenschaft zu vergleichen. Dies paßt zu den Symptomen, da kein zirkulärer Referenzfehler geworfen wird, obwohl es tatsächlich eine zirkuläre Referenz ist (und WcfTestClient.exe in die Luft geht) UND der ProxyDataContractResolver explodiert, wenn er die 'Config.Apps [x] .Configs [y]' Ebene erreicht von Konfigurationen (Es weiß nicht, wie man einen Config-Proxy abbildet. Der ProxyDataContractResolver funktioniert anders. Es ist, als ob er die erste Runde von Entitäten handhaben kann, aber die zweite Ebene als unterschiedliche Entitäten.)

Wow, ich kann sei wortwörtlich. Entschuldigung, Leute!

+0

Ich habe genau die gleiche Frage/Problem jetzt. Entitätsrahmen 5.0. Das Entity-Modell funktioniert, aber die Serialisierung kann nicht herausfinden, dass es nicht wieder zurück gehen sollte, wenn Sie die Viele-zu-viele-Beziehung –

+0

Hatten das gleiche Problem, löste mich. Hier 'die Lösung: http://StackOverflow.com/a/17063364/1386781 –

+0

WCFTestClient kann nicht umgehen Zirkelverweise. Sehen Sie diese [SO-Thread] [1] [1]: http://stackoverflow.com/questions/8686960/wcftestclient-exe-not-able-to-handle-circular-reference – MickyD

Antwort

0

Versuchen Sie die Einstellung myContext.ContextOptions.ProxyCreationEnabled = false;

Wenn das Problem (wie bei mir) gelöst wird dann haben Sie nicht die Schritte folgten erwähnt: http://msdn.microsoft.com/en-us/library/ee705457.aspx

Dies löste das Problem für mich.

+0

Ich habe es auf beide Arten gemacht: "Ich deaktiviere Lazy Loading und deaktiviere Proxy-Erstellung für den Kontext und lade explizit die Navigationseigenschaft (entweder durch .Include() oder .LoadProperty()). Allerdings wenn die Navigationseigenschaft geladen ist (Das heißt, Apps werden für eine bestimmte Konfiguration geladen.) Die App-Objekte, die bereits geladen wurden, enthalten bereits Verweise auf die Configs, die in den Speicher geladen wurden. Dadurch wird ein Zirkelverweis erstellt. " – kdawg

1

Hrmm, ich habe das Problem vielleicht nicht vollständig verstanden, aber jedes Mal, wenn ich auf zirkuläre Referenzen mit WCF stoße, lautet die Antwort, [DataContract] für die beanstandeten Klassen zu [DataContract (IsReference = true)] zu ändern.

Dies ist eine große Hilfe im Vergleich zu allen drek der Verwirrung mit den Vertragsresolver, die vor WCF 3.5 SP1 benötigt wurde.

Hoffe, das hilft.

2

Sie möchten vielleicht meine blog post on this specific scenario auschecken - bitte mailen Sie mir, wenn es nicht hilft, Ihre aktuelle missliche Lage zu beheben! Ich habe eine Beispiellösung auch eingeschlossen.

Bitte geben Sie mir Feedback in beide Richtungen, ich würde wirklich gerne von mehr Leuten zu diesem speziellen Thema hören - besonders mit den Implementierungsproblemen am Client Ende der Dinge.

+0

Hey Rob, ich habe versucht, die MSDN-Lösung und ich konnte eine Entity, aber nicht ohne ihre Objekte zu einer anderen Tabelle. Sage Bücher -> Autoren, ich bekomme nur Bücher, aber ich habe keine Autoren. Liegt es daran, dass sie nicht serialisiert wurden? –

+0

@LeoLuis Könnten Sie Lazy Loading aktiviert haben? – RobS

1

Konfrontiert das gleiche Problem heute und Value Injecter verwendet, um es zu lösen. Es ist so einfach wie:

var dynamicProxyMember = _repository.FindOne<Member>(m=>m.Id = 1); 
var member = new Member().InjectFrom(dynamicProxyMember) as Member; 

Wir leisten könnte nicht ProxyCreation deaktivieren

+1

Sie haben keine Ahnung, wie viel Zeit Sie mir heute gespart haben. – CoachNono

+0

froh, einem Mitentwickler @CoachNono geholfen zu haben – Korayem

0

Sie die ApplyDataContractResolverAttribute und ein ProxyDataContractResolver zusammen mit dem CyclicReferencesAwareAttribute verwenden können. Zunächst erzeugt diese Fehler wie diese - als ob es kein DataContractResolver überhaupt angegeben:

Typen ‚System.Data.Entity.DynamicProxies.Whatever_E6 ...... A9‘ mit Datenvertrag Namen ‚Whatever_E6 ...... A9: http: //schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies 'wird nicht erwartet. Ziehen Sie die Verwendung eines DataContractResolvers in Betracht oder fügen Sie statisch unbekannte Typen zur Liste bekannter Typen hinzu, z. B. indem Sie das KnownTypeAttribute-Attribut verwenden oder diese zur Liste bekannter Typen hinzufügen, die an DataContractSerializer übergeben werden.

Es wird mit einer einfachen Änderung arbeiten.

Im ApplyCyclicDataContractSerializerOperationBehavior müssen die Konstruktoren für den DataContractSerializer auch den DataContractResolver übergeben. Dies ist von allen Versionen, die ich online gesehen habe, weggelassen.

Beispiel:

public class ApplyCyclicDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior 
{ 
    private readonly Int32 _maxItemsInObjectGraph; 
    private readonly bool _ignoreExtensionDataObject; 

    public ApplyCyclicDataContractSerializerOperationBehavior(OperationDescription operationDescription, Int32 maxItemsInObjectGraph, bool ignoreExtensionDataObject, bool preserveObjectReferences) 
     : base(operationDescription) 
    { 
     _maxItemsInObjectGraph = maxItemsInObjectGraph; 
     _ignoreExtensionDataObject = ignoreExtensionDataObject; 
    } 

    public override XmlObjectSerializer CreateSerializer(Type type, String name, String ns, IList<Type> knownTypes) 
    { 
     return new DataContractSerializer(type, name, ns, knownTypes, 
      _maxItemsInObjectGraph, 
      _ignoreExtensionDataObject, 
      true, 
      null /*dataContractSurrogate*/, 
      DataContractResolver); // <----------------------------- 
    } 

    public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes) 
    { 
     return new DataContractSerializer(type, name, ns, knownTypes, 
      _maxItemsInObjectGraph, 
      _ignoreExtensionDataObject, 
      true, 
      null /*dataContractSurrogate*/, 
      DataContractResolver); // <----------------------------- 
    } 
}