Обзор
Я пытаюсь написать веб-службу с использованием ASP.NET Core, которая позволяет клиентам запрашивать и изменять состояние микроконтроллера. Этот микроконтроллер содержит ряд систем, которые я моделирую в своем приложении - например, систему ШИМ, систему ввода исполнительного механизма и т. Д.
Все компоненты этих систем имеют определенные свойства, которые можно запросить или изменить с помощью патча JSON. запрос. Например, 4-й PWM на микроконтроллере можно включить с помощью HTTP-запроса, несущего {"op":"replace", "path":"/pwms/3/enabled", "value":true}
. Для поддержки этого я использую библиотеку AspNetCore.JsonPatch
.
Моя проблема в том, что я пытаюсь реализовать поддержку JSON Patch для новой системы «базы данных CAN», которая логически должна сопоставлять имя определения с определением конкретного сообщения CAN, и я не уверен, как это сделать. иди об этом.
Подробности
На диаграмме ниже моделируется система базы данных CAN. Экземпляр CanDatabase
должен логически содержать словарь формы IDictionary<string, CanMessageDefinition>
.
Для поддержки создания новых определений сообщений мое приложение должно позволять пользователям отправлять запросы на исправление JSON следующим образом:
{
"op": "add",
"path": "/candb/my_new_definition",
"value": {
"template": ["...", "..."],
"repeatRate": "...",
"...": "...",
}
}
Здесь my_new_definition
будет определять определение имя, а объект, связанный с value
, должен быть десериализован в CanMessageDefinition
объект. Затем его следует сохранить как новую пару "ключ-значение" в словаре CanDatabase
.
Проблема в том, что path
должен указывать путь к свойству, который для статически типизированных объектов будет ... ну, статическим (исключением является то, что он позволяет ссылаться на элементы массива em > например, /pwms/3
, как указано выше).
Что я пробовал
А. Подход Лироя Дженкинса
Забудьте о том, что я знаю, что это не сработает - я попробовал реализацию ниже (которая использует только статическую типизацию, несмотря на то, что мне нужно поддерживать динамические пути JSON Patch), просто чтобы посмотреть, что произойдет.
Реализация
internal sealed class CanDatabaseModel : DeviceComponentModel<CanDatabaseModel>
{
public CanDatabaseModel()
{
this.Definitions = new Dictionary<string, CanMessageDefinition>();
}
[JsonProperty(PropertyName = "candb")]
public IDictionary<string, CanMessageDefinition> Definitions { get; }
...
}
Тест
{
"op": "add",
"path": "/candb/foo",
"value": {
"messageId": 171,
"template": [17, 34],
"repeatRate": 100,
"canPort": 0
}
}
Результат
InvalidCastException
выдается на сайт, где я пытаюсь применить указанные изменения к JsonPatchDocument
.
Сайт:
var currentModelSnapshot = this.currentModelFilter(this.currentModel.Copy());
var snapshotWithChangesApplied = currentModelSnapshot.Copy();
diffDocument.ApplyTo(snapshotWithChangesApplied);
Исключение:
Unable to cast object of type 'Newtonsoft.Json.Serialization.JsonDictionaryContract' to type 'Newtonsoft.Json.Serialization.JsonObjectContract'.
Б. Использование динамического исправления JSON
Более многообещающий план атаки, казалось, полагался на динамическое исправление JSON, которое включает выполнение операций исправления на экземпляры ExpandoObject
. Это позволяет вам использовать патч-документы JSON для добавления, удаления или замены свойств, поскольку вы имеете дело с динамически типизированным объектом.
Реализация
internal sealed class CanDatabaseModel : DeviceComponentModel<CanDatabaseModel>
{
public CanDatabaseModel()
{
this.Definitions = new ExpandoObject();
}
[JsonProperty(PropertyName = "candb")]
public IDictionary<string, object> Definitions { get; }
...
}
Тест
{
"op": "add",
"path": "/candb/foo",
"value": {
"messageId": 171,
"template": [17, 34],
"repeatRate": 100,
"canPort": 0
}
}
Результат
Внесение этого изменения позволяет этой части моего теста работать без возникновения исключений, но JSON Patch не знает, что десериализовать value
как, в результате чего данные сохраняются в словаре как JObject
, а не как CanMessageDefinition
:
Можно ли «сказать» JSON Patch, как десериализовать информацию случайно? Возможно, что-то вроде использования атрибута JsonConverter
на Definitions
?
[JsonProperty(PropertyName = "candb")]
[JsonConverter(...)]
public IDictionary<string, object> Definitions { get; }
Резюме
- Мне нужно поддерживать запросы патчей JSON, которые добавляют значения в словарь
- Я пробовал идти по чисто статическому маршруту, но это не удалось.
- I've tried using dynamic JSON patching
- This partly worked, but my data was stored as a
JObject
type instead of the intended type - Есть ли атрибут (или какой-либо другой метод), который я могу применить к своему свойству, чтобы позволить ему десериализоваться до правильного типа (не анонимного типа)?
- This partly worked, but my data was stored as a
template
вvalue
объекте? Можем ли мы переместитьmessageId
иtemplate
в родительский объект? - person Ankit   schedule 16.01.2017template
представляет собой полезную нагрузку сообщения CAN (0-8 байтов), поэтому это будет массив целых чисел.messageId
иtemplate
должны оставаться в прежнем виде, поскольку запросы должны соответствовать схеме JSON Patch, как описано в RFC 6902 - person Tagc   schedule 16.01.2017PropertyChanged
вExpandoObject
, чтобы вручную преобразовать новыйJObject
вCanMessageDefinition
). - person Tagc   schedule 17.01.2017IDictionary<T, K>
. Вы пробовали просто использоватьDictionary<T, K>
? Я использую это и не имею никаких проблем. - person Sinaesthetic   schedule 01.07.2019