Wie kann ich in meinem REST WCF-Dienst beliebige JSON-Objekte akzeptieren?

8

Ich möchte eine Service-Methode wie folgt implementieren:

%Vor%

Meine Kunden POST-Objekte mögen:

%Vor%

Beim Aufruf von MakeCircle hätte moreArgs drei Einträge ("radius", "filled" und ein Wörterbuch namens "annotation", das zwei Schlüssel / Wert-Paare enthält).

Das Beste, was ich bisher habe, ist:

%Vor%

Ich könnte mit einer solchen Lösung leben, außer dass Schritt 3 schmerzhaft sein wird, um über Dutzende von Methoden hinweg zu synchronisieren. Offensichtlich muss etwas das Wörterbuch öffnen und die zusätzlichen Argumente verwenden, aber ich möchte diesen Code lieber aus meiner Kommunikationsschicht heraushalten. IMO geht es in die Geschäftslogik, die über die Argumente weiß (in diesem Fall durch MakeCircle dargestellt).

Ich mag das automatische Binden von WCF sehr, weil es diese fehleranfälligen manuellen Übersetzungen eliminiert. Ich wünschte, es gäbe eine Möglichkeit, es für fast alles zu verwenden, außer dass Sie ein wenig zusätzliche Logik für die Argumente angeben, die es nicht zuordnen kann. Vielleicht gibt es eine Art Service-Verhalten, das sagt "übergib sie an [diesen Code] und ich werde damit umgehen"?

Ich habe die von IExtensibleDataObject angebotene "Rundum-Auslösung" in Betracht gezogen, aber es scheint meinem Code keinen Zugang zu den unbekannten Eigenschaften zu geben - sie sind nur für den Zweck der Rücksendung an den Client eingepackt. Ссылка

Eine andere Option wäre, eine benutzerdefinierte Klasse zu verwenden, die ein IDictionary enthält, und die Deserialisierung irgendwie selbst zu übernehmen. Also wäre die Service-Methode: [OperationVertrag] [WebInvoke (RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)] public void MakeShape (Zeichenfolgenform, Zeichenfolgenfarbe, MoreArgs moreArgs)

Und ich müsste Kunden in eine strengere Struktur zwingen:

%Vor%

Das ist nicht ideal, aber ich könnte damit leben. Die Frage wird, wie man MoreArgs definiert und eine richtig aufgefüllt bekommt. Mein nächster Versuch:

%Vor%

Dies löst eine InvalidDataContractException beim Dienststart aus (... MoreArgs 'kann nicht ISerializable sein und das DataContractAttribute-Attribut haben.)

Das Entfernen des [DataContract] -Attributs löst die InvalidDataContractException aus, die ich erwarte (... MoreArgs 'kann nicht serialisiert werden. Erwägen, es mit dem DataContractAttribute-Attribut zu markieren ...).

Wie erwartet, löscht das Entfernen der ISerializable-Vererbung die Ausnahme, führt jedoch dazu, dass moreArgs.Properties beim Aufruf von MakeCircle null ist.

Ich frage mich auch, ob es eine Hybridlösung gibt, die ich verwenden kann? Vielleicht:

  • Übernehmen Sie einen Stream und erstellen Sie das Argumentwörterbuch wie bei meinem ersten Versuch
  • Definieren Sie die Methode mit einem MoreArgs-Argument wie meinem späteren Versuch
  • Füllen Sie ein MoreArgs-Objekt aus dem Wörterbuch aus dem Stream
  • Irgendwie rufen Sie WCF erneut an und sagen: "Rufen Sie die Methode auf, die aufgerufen würde, wenn Sie diese Argumente hätten" (indem Sie das ursprüngliche Argumentwörterbuch und die neuen korrekt befüllten MoreArgs angeben).

MoreArgs würde dann auch die ursprünglichen Argumente enthalten, aber das ist wahrscheinlich keine Katastrophe. Ich denke, ich könnte wahrscheinlich den Anruf, den ich brauche, mit Reflektion machen, aber das fühlt sich albern an, wenn WCF diese Funktion intern haben muss, debuggt und optimiert, um zu booten.

    
solublefish 13.07.2012, 07:18
quelle

1 Antwort

3

@Melissa Avery-Wehr

Ich bin nicht glücklich mit meiner "Lösung", aber ich musste weitermachen.

Beim App-Start stacke ich für jede Methode, die ich aufrufen möchte, eine MethodInfo in eine Nachschlagetabelle. Es wird durch einen Interface- und Methodennamen kodiert. Ich benutze Reflexion und ein benutzerdefiniertes Attribut, um sie zu finden, aber eine beliebige Anzahl von Techniken könnte hier funktionieren.

Meine eine WCF-Dienstmethode akzeptiert einen Schnittstellennamen, einen Methodennamen und einen Stream als Argumente. Ich verwende JSON.NET, um Argumente für ein Dictionary zu deserialisieren und an meinen Dispatcher zu übergeben.

Der Dispatcher sucht MethodInfo nach dem Namen der Schnittstelle und der Methode. Dann, passende Argumente aus dem Wörterbuch zu Parametern in der MethodInfo, fülle ich ein Argumentarray. Wenn die Zielmethode tatsächlich einen Dictionary-moreArgs-Parameter aufweist, werden alle nicht übereinstimmenden Argumente abgerufen. Schließlich rufe ich MethodInfo.Invoke auf und übergebe das frisch befüllte Argumentarray.

Es ist eine Menge fiddly Code, um einige Dinge zu tun, die WCF fast für mich tut, aber ich habe keine bessere Lösung gefunden.

Es gibt einige Vorteile, all das selbst zu kontrollieren. Mein Favorit ist die Möglichkeit, die gespeicherten MethodInfos zu verwenden, um clientseitige Anruf-Stubs automatisch in der gewünschten Sprache zu generieren.

Wenn sich die späte Bindung als Leistungsproblem herausstellt, werde ich in Betracht ziehen, alle Anrufe manuell in einen großen Schalter (methodName) zu setzen. Wenn sich meine Schnittstellen immer noch häufig ändern, kann ich versuchen, diesen Blockcode als Build-Schritt zu generieren. Wahrscheinlich werde ich mich nie darum kümmern, da ich bei DB-Zugriffen einen Engpass haben werde.

    
solublefish 09.01.2013, 00:13
quelle

Tags und Links