Web Api - проблема с сериализацией данных в теле происходит с нулевыми значениями в неиспользуемых свойствах DTO - PullRequest
0 голосов
/ 09 января 2020

Я использую метод веб-API для обновления базы данных с использованием платформы лица. Я столкнулся с проблемой при реализации метода обновления.

BoxDto имеет 20 свойств , но в этом случае клиент хочет обновить только 1 свойство. Я использую Почтальон, чтобы отправить этот запрос.

 PUT -  {{ServerPath}}/api/boxes/{id}
           row data:
                {
                     "LastPrintedBy" : "ABC"
                }

вот мой метод контроллера webapi:

public HttpResponseMessage UpdateBox(int id, BoxDto box)
{
}

Здесь, BoxDto box будет корректно извлекать значение LastPrintedBy, но все остальные оставшиеся свойства получат значение Null , Это будет проблемой в классе AutoMapper, потому что я реализовал правило, чтобы игнорировать нулевые значения при автоматическом сопоставлении с таблицей БД. Поскольку в случае, если клиент хочет установить какое-либо поле пустым, Контроллер не может понять, что автоматически устанавливается нулевое значение с помощью сериализатора или переданного Клиентом значения.

Посоветуйте, пожалуйста, способ решения этой проблемы.

Ответы [ 4 ]

2 голосов
/ 09 января 2020

Невозможно, чтобы autopperpper знал, является ли нулевое значение из сериализации или установлено клиентом, что вы можете сделать, это удалить правило автоматического сопоставления, которое игнорирует нулевые значения, а затем передать все значения (даже если вы не обновляя его) в DTO.

PUT -  {{ServerPath}}/api/boxes/{id}
           row data:
                {
                     "LastPrintedBy" : "ABC",
                     "Property two"  : "Updated Value",
                     "Property three"  : "Same value",
                     "Property four" : null <- null set by client
                }
1 голос
/ 10 января 2020

То, что вы ищете, обычно известно как частичное обновление ресурса, и может быть достигнуто с помощью JSON Patch.

Пожалуйста, обратитесь к этой статье https://dotnetcoretutorials.com/2017/11/29/json-patch-asp-net-core/.

0 голосов
/ 13 января 2020

Спасибо за все ваши идеи и советы. И я нашел альтернативу, получив все ваши мысли и советы. Надеюсь, эта опция будет полезна для некоторых из вас в соответствии с вашим сценарием.

  [HttpPut]
        public HttpResponseMessage UpdateBox(HttpRequestMessage requestMsg, int boxId, JObject boxObj) // Step 1 : Change the input type C# Object to JObject
        {
            //Step 2: Get the Box entity instance by calling Get method. Save to Dto 
            BoxDto boxDto = _boxCommonService.GetBox(boxId);
            try
            {
                // Step 3: Iterate the JObject and find is there any user set, Null values.
                foreach (var prop in boxObj)
                {
                    string key = prop.Key;
                    JToken value = prop.Value;
                    PropertyInfo propertyInfo = boxDto.GetType().GetProperty(key);
                    if (boxDto.GetType().GetProperty(key) == null)
                    {
                        return requestMsg.CreateResponse(HttpStatusCode.BadRequest, "invalid property name");
                    }
                    else
                    {
                        // Step 4: If there is any, update the Dto
                        boxDto.GetType().GetProperty(key).SetValue(boxDto, Convert.ChangeType(value, propertyInfo.PropertyType), null);
                    }
                }
                // Step 5: Now you can call the service with auttomapper to map the entity with Dto. (Remove any autoMapper rule to ignore null values)           
                _boxCommonService.UpdateBox(boxId, boxDto);
);

Я полагаю, что это удобный способ для клиентского приложения, без какой-либо ответственности перед клиентом, запрашивая метод Get перед обновлением. И использовать встроенные возможности автопроизводителя тоже.

0 голосов
/ 10 января 2020

Рассмотрим два варианта:

Вариант 1. Один метод обновления, но он должен принимать полное представление DTO. Если пользователь обновляет 1 значение, все немодифицированные значения включаются. В вашем примере, как вы ожидаете, что клиент сможет сообщить серверу «Установите это значение на #null»?

Вариант 2: Организовать API в действиях. Часто клиент не может обновить каждую деталь в объекте. Они могут выполнять действия, которые приводят к обновлению некоторых полей. Действие «PrintBox» или «UpdateBoxLabel» может либо явно, либо неявно обновить одно из них, либо выбрать несколько свойств для объекта блока.

Преимущество варианта 2 состоит в том, что он явно разбивает вещи, но это приводит к большему количеству кода, но простому коду в вашем API. Проблема с вариантом 1 состоит в том, что в большинстве случаев у клиента не должно быть разрешений бланширования корзины для изменения чего-либо и всего в сущности. Ваш клиентский код может позволять обновлять только некоторые детали, записывать их в DTO и отправлять на сервер, но ваш сервер должен абсолютно проверять, обновляются ли только допустимые значения и являются ли они действительными. Веб-запросы могут быть перехвачены пользователем в браузере или даже вредоносными плагинами, которые могут подделать данные до того, как сервер их получит. С вариантом 2 вам все еще нужно проверить, но занимаемая площадь намного меньше.

Например, с вариантом 2, если у вас есть действие с именем «PrintBoxLabel (boxId)», это действие может (в качестве примера): - Утверждение, что запись о boxId существует. - Утверждать, что текущий сеанс пользователя имеет доступ к этому полю. - Подготовьте PDF / отчет для ярлыка коробки. - Получить идентификатор пользователя из текущего сеанса и обновить значение LastPrintedBy записи Box и значение LastPrintedOn. - Верните PDF.

Вместо вызова клиента для печати, затем вызовите метод "UpdateBox". В предыдущем примере просто нужен идентификатор Box, остальное происходит из сеанса сервера. Если вы действительно хотите отправить данные с клиента, методы API предназначены для принятия только тех данных, которые разрешено обновлять, их проверки, а затем выполнения соответствующих действий. Система менее уязвима для неожиданного вмешательства.

...