Ich versuche, einen Webdienst mit ASP.NET Core zu schreiben, mit dem Clients den Status eines Mikrocontrollers abfragen und ändern können. Dieser Mikrocontroller enthält eine Reihe von Systemen, die ich in meiner Anwendung modelliere - zum Beispiel ein PWM-System, ein Aktor-Eingabesystem usw.
Die Komponenten dieser Systeme haben alle bestimmte Eigenschaften , die mit einer JSON-Korrektur Anfrage abgefragt oder geändert werden können. Zum Beispiel kann die 4. PWM auf dem Mikro über eine HTTP-Anfrage mit {"op":"replace", "path":"/pwms/3/enabled", "value":true}
aktiviert werden. Um dies zu unterstützen, verwende ich die AspNetCore.JsonPatch
Bibliothek.
Mein Problem ist, dass ich versuche, die JSON-Patch-Unterstützung für ein neues "CAN-Datenbank" -System zu implementieren, das einen Definitionsnamen logisch einer bestimmten CAN-Nachrichtendefinition zuordnen sollte, und ich nicht sicher, wie man das macht.
Das folgende Diagramm modelliert das CAN-Datenbanksystem. Eine CanDatabase
-Instanz sollte logisch ein Wörterbuch der Form IDictionary<string, CanMessageDefinition>
enthalten.
Um das Erstellen neuer Nachrichtendefinitionen zu unterstützen, sollte meine Anwendung Benutzern erlauben, JSON-Patch-Anfragen wie folgt zu senden:
%Vor% Hier würde my_new_definition
die Definition Name definieren und das mit value
verknüpfte Objekt sollte zu einem CanMessageDefinition
Objekt deserialisiert werden. Dies sollte dann als neues Schlüssel-Wert-Paar im CanDatabase
-Wörterbuch gespeichert werden.
Das Problem ist, dass path
einen Eigenschaftspfad angeben sollte, der für statisch typisierte Objekte ... na ja, statisch wäre (eine Ausnahme davon ist, dass man referenzieren kann) Array-Elemente zB /pwms/3
wie oben).
A. Der Ansatz Leeroy Jenkins
Vergessen Sie die Tatsache, dass ich weiß es wird nicht funktionieren - Ich habe versucht, die Implementierung unten (die statische Eingabe nur verwendet, obwohl ich dynamische JSON Patch-Pfade unterstützen muss) nur um zu sehen, was passiert.
Implementierung
%Vor%Test
%Vor%Ergebnis
Ein InvalidCastException
wird an der Stelle geworfen, an der ich versuche, die angegebenen Änderungen auf JsonPatchDocument
anzuwenden.
Seite:
%Vor%Ausnahme:
%Vor%B. Verlassen Sie sich auf dynamisches JSON-Patching
Ein vielversprechender Angriffsplan schien sich auf dynamisches JSON-Patching zu stützen, bei dem Patch-Operationen auf Instanzen von %Code%. Dadurch können Sie JSON-Patch-Dokumente zum Hinzufügen, Entfernen oder Ersetzen von Eigenschaften verwenden, da Sie mit einem dynamisch typisierten Objekt arbeiten.
Implementierung
%Vor%Test
%Vor%Ergebnis
Durch diese Änderung kann dieser Teil meines Tests ausgeführt werden, ohne dass Ausnahmen ausgelöst werden, aber JSON Patch weiß nicht, wie ExpandoObject
as deserialisiert werden soll. Dies führt dazu, dass die Daten im Wörterbuch als value
gespeichert werden a JObject
:
Wäre es möglich, JSON Patch zu sagen, wie man die Informationen zufällig deserialisiert? Vielleicht etwas in Richtung der Verwendung eines Attributs CanMessageDefinition
in JsonConverter
?
Definitions
type anstatt des beabsichtigten Typs Da es keinen offiziellen Weg dafür zu geben scheint, habe ich eine Temporary Solution ™ (eine Lösung, die gut genug funktioniert, damit ich sie für immer aufbewahre) entwickelt.
> Um den Eindruck zu erwecken, dass JSON Patch wörterbuchartige Operationen handhabt, habe ich eine Klasse namens DynamicDeserialisationStore
erstellt, die von DynamicObject
und nutzt die Unterstützung von JSON Patch für dynamische Objekte.
Genauer gesagt überschreibt diese Klasse Methoden wie TrySetMember
, TrySetIndex
, TryGetMember
usw., um sich im Wesentlichen wie ein Wörterbuch zu verhalten, mit der Ausnahme, dass sie alle diese Operationen an Rückrufe ihres Konstruktors delegiert.
Implementierung
Der folgende Code enthält die Implementierung von DynamicDeserialisationStore
. Es implementiert IDictionary<string, object>
(das ist die Signatur, die JSON Patch benötigt, um mit dynamischen Objekten zu arbeiten), aber ich implementiere nur das Minimum der Methoden, die ich benötige.
Das Problem mit der Unterstützung von dynamischen Objekten durch JSON Patch besteht darin, dass Eigenschaften auf JObject
instances gesetzt werden, d. h. die Deserialisierung wird nicht automatisch durchgeführt, wie dies beim Festlegen statischer Eigenschaften der Fall wäre, da der Typ nicht abgeleitet werden kann. DynamicDeserialisationStore
wird für den Objekttyp parametrisiert, der versucht, diese JObject
Instanzen automatisch zu deserialisieren, wenn sie gesetzt sind.
Die Klasse akzeptiert Callbacks, um grundlegende Dictionary-Operationen zu behandeln, anstatt ein internes Dictionary selbst zu verwalten, weil ich in meinem "echten" Systemmodell-Code kein Wörterbuch verwende (aus verschiedenen Gründen) - ich lasse es einfach so aussehen an Kunden.
%Vor%Tests
Die Tests für diese Klasse sind unten aufgeführt. Ich erstelle ein falsches Systemmodell (siehe Bild) und führe verschiedene JSON-Patch-Operationen darauf aus.
Hier ist der Code:
%Vor%Tags und Links c# json-patch