Asp web api patch реализация - программирование
Подтвердить что ты не робот

Asp web api patch реализация

Предположим, что у меня есть эта модель

public partial class Todo
{
    public int id { get; set; }
    public string content { get; set; }
    public bool done { get; set; }
}

И я отправляю это как данные json на свой контроллер в качестве запроса на исправление. Это мучительно действие toggeling checkbox. Я думаю, что это означает, что я только хочу отправить это на свой сервер, а не всю модель.

{ "id":1, "done" : true }

Что должен сделать мой контроллер WebApi, чтобы правильно обработать этот простой запрос json-патча? Должен ли я использовать web api для этого, или я должен использовать более rpc-стиль с mvc?

Кажется, что это очень простая вещь, но я не могу понять, что это правильно! Я думаю, мне может понадобиться использовать другой параметр в моем методе контроллера, но я не уверен.

Спасибо за ваше время.

4b9b3361

Ответ 1

Вы можете найти функцию PATCH в пакете Nuget перед выпуском OData: Microsoft.AspNet.WebApi.OData.

Информация о том, как вы можете использовать его для создания действия для обработки PATCH, можно найти в разделе "Частичные обновления" (запросы PATCH) в сообщении в блоге о Поддержка OData в веб-интерфейсе ASP.NET.

Ответ 2

Изменение метода PATCH никак не изменяет поведение Web API. Для частичных обновлений нет встроенного механизма. Одна из причин отсутствия такого метода PATCH так долго, что нет вездесущего типа носителя для применения исправлений к ресурсам.

Во-вторых, вы просите Web API выполнить сериализацию объектов для вас, поэтому просто не существует такой концепции применения частично обновленного объекта. Было бы так много соглашений, чтобы договориться о том, что означает значение null, а что о пустом значении, как я могу сказать "не обновлять этот DateTime". Что относительно связанных объектов, дочерних элементов? Как вы можете удалить дочерний элемент? Если команда CLR не реализует некоторую концепцию типа, содержащего только подмножество членов другого типа, частичные обновления и сериализация объектов не собираются вместе.

Aliostad упоминает UpdateModel, и это возможно при обновлении из HTML-формы, потому что тип носителя application/x-www-form-urlencoded явно допускает произвольный набор пар значений имени. Серийной обработки объектов не происходит. Это просто совпадение имен из формы, сопоставляемой именам объекта Model.

Для себя я создал новый тип носителя, который я использую для частичных обновлений, которые работают как форма, но более продвинутые, поскольку они могут обрабатывать иерархические данные и поддерживают порядок обновлений.

Ответ 4

Я использовал Microsoft.AspNet.WebApi.OData для моего проекта, и у меня были некоторые проблемы с JSON (работа с числами в моем случае). Кроме того, пакет OData имеет некоторые зависимости, которые, с моей точки зрения, слишком велики для одной функции (~ 7 МБ со всеми зависимостями).

Итак, я разработал простую библиотеку, которая делает то, о чем вы просите: SimplePatch.

Как использовать

Установите пакет, используя:

Install-Package SimplePatch

Затем в вашем контроллере:

[HttpPatch]
public IHttpActionResult PatchOne(Delta<Todo> todo)
{
    if (todo.TryGetPropertyValue(nameof(Todo.id), out int id)) {
        // Entity to update (from your datasource)
        var todoToPatch = Todos.FirstOrDefault(x => x.id == id);
        if (todoToPatch == null) return BadRequest("Todo not found");

        todo.Patch(todoToPatch);     

        // Now todoToPatch is updated with new values            
    } else {
        return BadRequest();
    }     

    return Ok();
}

В библиотеке также поддерживается массивный патч:

[HttpPatch]
public IHttpActionResult PatchMultiple(DeltaCollection<Todo> todos)
{
    foreach (var todo in todos)
    {
        if (todo.TryGetPropertyValue(nameof(Todo.id), out int id))
        {
            // Entity to update (from your datasource)
            var entityToPatch = Todos.FirstOrDefault(x => x.id == Convert.ToInt32(id));
            if (entityToPatch == null) return BadRequest("Todo not found (Id = " + id + ")");

            person.Patch(entityToPatch);
        }
        else
        {
            return BadRequest("Id property not found for a todo");
        }
    }

    return Ok();
}

Если вы используете Entity Framework, вам нужно добавить только две строки кода после вызова метода Patch:

entity.Patch(entityToPatch);

dbContext.Entry(entityToPatch).State = EntityState.Modified;
dbContext.SaveChanges();

Кроме того, вы можете исключить некоторые свойства, которые будут обновляться при вызове метода Patch. Global.asax или Startup.cs

DeltaConfig.Init((cfg) =>
{
    cfg.ExcludeProperties<Todo>(x => x.id);
});

Это полезно, когда вы работаете с сущностью, и вы не хотите создавать модель.