Как выполнить ПАТЧ в веб-API и OData

Из спецификации RFC глагола Patch становится ясно, что глагол Patch не должен принимать значения для частично обновить сущность, но выполнить следующие операции:

... Однако с PATCH закрытый объект содержит набор инструкций, описывающих, как ресурс, находящийся в данный момент на исходном сервере, должен быть изменен для создания новой версии.

В MSDN для класса Delta это также ясно, поскольку В описании патча говорится:

Заменяет исходный объект с помощью изменений, отслеживаемых этой дельтой.

В отличие от описания Put:

Заменяет исходный объект значениями, хранящимися в этой дельте.

Пока все хорошо, но я не мог найти способ отправить эти «инструкции» с помощью OData. Что бы я ни делал, Delta.Patch заменяет только значения.

Каким должен быть синтаксис запроса на исправление?

Я пробовал следующие способы:

PATCH http://localhost:55783/Products(1) HTTP/1.1
User-Agent: Fiddler
Host: localhost:55783
Content-Length: 19
Content-type: application/json

{ "Price": 432 }

А также

{ "op": "add", "path": "/Price", "value": 423432 }

И прочее рядом с этим.


Обновление:

Спасибо Майклу Муру и прочтению всего класса Delta с помощью ILSpy, я думаю, что это действительно ошибка в дизайне команды Patch.
Я обнаружил ошибку для Microsoft, вы можете проголосовать за нее, если вам тоже нужно ее исправить.


person gdoron is supporting Monica    schedule 01.09.2014    source источник


Ответы (1)


Я не уверен, что то, чего вы пытаетесь достичь, возможно. По крайней мере, не с Delta<TEntity>.Patch(..)

Предполагая, что у вас есть Product сущность и где-то в вашем PATCH действии у вас есть

[AcceptVerbs("PATCH")]
public void Patch(int productId, Delta<Product> product)
{
    var productFromDb = // get product from db by productId
    product.Patch(productFromDb);
    // some other stuff
}

Когда создается product, он внутри вызывает конструктор Delta<TEntityType>, который выглядит следующим образом (конструктор без параметров также вызывает этот конструктор, передавая typeof(TEntityType)

public Delta(Type entityType)
{
    this.Initialize(entityType);
}

Initialize метод выглядит так

private void Initialize(Type entityType)
{
    // some argument validation, emitted for the sake of brevity 

    this._entity = (Activator.CreateInstance(entityType) as TEntityType);
    this._changedProperties = new HashSet<string>();
    this._entityType = entityType;
    this._propertiesThatExist = this.InitializePropertiesThatExist();
}

Интересной частью здесь является this._propertiesThatExist, который является Dictionary<string, PropertyAccessor<TEntityType>>, который содержит свойства типа Product. PropertyAccessor<TEntityType> - это внутренний тип, позволяющий упростить управление свойствами.

Когда вы звоните product.Patch(productFromDb), это то, что происходит под капотом

// some argument checks
PropertyAccessor<TEntityType>[] array = (
        from s in this.GetChangedPropertyNames()
        select this._propertiesThatExist[s]).ToArray<PropertyAccessor<TEntityType>>();

    PropertyAccessor<TEntityType>[] array2 = array;

    for (int i = 0; i < array2.Length; i++)
    {
        PropertyAccessor<TEntityType> propertyAccessor = array2[i];
        propertyAccessor.Copy(this._entity, original);
    }

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

propertyAccessor.Copy(this._entity, original) тело метода

public void Copy(TEntityType from, TEntityType to)
{
    if (from == null)
    {
        throw Error.ArgumentNull("from");
    }
    if (to == null)
    {
        throw Error.ArgumentNull("to");
    }
    this.SetValue(to, this.GetValue(from));
}
person Michael    schedule 01.09.2014
comment
Спасибо за Ваш ответ! У меня было ощущение, что использование отражателя может быть здесь полезным ... Так это ошибка? Поскольку спецификация и MSDN говорят об инструкциях, а не о значениях. Так в чем же разница между Delta.Put и Delta.Patch? Кстати, вы работаете в Microsoft или только программист-энтузиаст? - person gdoron is supporting Monica; 02.09.2014
comment
@gdoron, вы говорите о MSDN для метода исправлений Delta? - person Michael; 02.09.2014
comment
@gdoron вы, вероятно, удивитесь, но метод Delta PUT не сильно отличается, единственное отличие состоит в том, что в методе PUT он также проходит через список неизмененных свойств и также просто копирует эти значения. И нет, я не работаю в MS :) Кстати, в качестве примечания - я использовал IlSpy, а не рефлектор :) - person Michael; 02.09.2014
comment
@gdoron, как вы упомянули в сообщении, просто говорит, что он перезаписывает исходный объект с изменениями, отслеживаемыми Delta. Вы видели, как Delta отслеживает изменения, она не ищет инструкций, и нигде в MSDN я не нашел ни слова о инструкциях. Я согласен с вами, RFC spec говорит об инструкциях. - person Michael; 02.09.2014
comment
Так вы говорите, что Delta.Put не обновляет сущность частично, а полностью переопределяет сущность, как простой метод Http put ?! - person gdoron is supporting Monica; 02.09.2014
comment
Позвольте нам продолжить это обсуждение в чате. - person Michael; 02.09.2014
comment
Я обнаружил ошибку для Microsoft Спасибо! - person gdoron is supporting Monica; 02.09.2014
comment
Вы можете использовать [HttpPatch] вместо [AcceptVerbs("PATCH")]. - person ; 24.05.2016