AspNetCoreOData icon indicating copy to clipboard operation
AspNetCoreOData copied to clipboard

@removed in a delta patch request results in a null delta object

Open corranrogue9 opened this issue 2 years ago • 4 comments

Assemblies affected Current

Describe the bug A delta PATCH request that contains an element with @removed results in a null Delta<T> object in the controller method.

Reproduce steps This request:

PATCH http://localhost:12197/v1/ForwardingPolicies/320343815
Content-Type: application/json
{
  "@odata.context": "#$delta",
  "PolicyRules@delta": [
    {
      "@odata.type": "Microsoft.Naas.Contracts.ControlPlane.MsGraphModels.Rules.m365ForwardingRule",
      "@removed": {"reason": "deleted"},
      "@id": "foobar"
    }
  ]
}

results in a 500 instead of a 200 when run against this branch.

Data Model Please see the linked branch.

EDM (CSDL) Model Please see the linked branch.

Request/Response 500.

Expected behavior 200.

corranrogue9 avatar Nov 07 '23 15:11 corranrogue9

Microsoft.OData.ODataException: Encountered a deleted entity when reading a non-delta response payload. Deleted entities are only supported in request payloads and delta responses.\r\n at Microsoft.OData.JsonLight.ODataJsonLightResourceDeserializer.ReadEntryInstanceAnnotationAsync(String annotationName, Boolean anyPropertyFound, Boolean typeAnnotationFound, PropertyAndAnnotationCollector propertyAndAnnotationCollector)\r\n at Microsoft.OData.JsonLight.ODataJsonLightResourceDeserializer.ReadODataOrCustomInstanceAnnotationValueAsync(IODataJsonLightReaderResourceState resourceState, PropertyParsingResult propertyParsingResult, String annotationName)\r\n at Microsoft.OData.JsonLight.ODataJsonLightResourceDeserializer.<>c__DisplayClass50_0.<<ReadResourceContentAsync>b__0>d.MoveNext()\r\n--- End of stack trace from previous location ---\r\n at Microsoft.OData.JsonLight.ODataJsonLightDeserializer.ProcessPropertyAsync(PropertyAndAnnotationCollector propertyAndAnnotationCollector, Func2 readPropertyAnnotationValueDelegate, Func3 handlePropertyDelegate)\r\n at Microsoft.OData.JsonLight.ODataJsonLightResourceDeserializer.ReadResourceContentAsync(IODataJsonLightReaderResourceState resourceState)\r\n at Microsoft.OData.JsonLight.ODataJsonLightReader.StartReadingResourceAsync()\r\n at Microsoft.OData.JsonLight.ODataJsonLightReader.ReadResourceSetItemStartAsync(PropertyAndAnnotationCollector propertyAndAnnotationCollector, SelectedPropertiesNode selectedProperties)\r\n at Microsoft.OData.JsonLight.ODataJsonLightReader.ReadNextResourceSetItemAsync()\r\n at Microsoft.OData.JsonLight.ODataJsonLightReader.ReadAtResourceSetStartInternalImplementationAsync()\r\n at Microsoft.OData.ODataReaderCoreAsync.ReadAsynchronously()\r\n at Microsoft.OData.ODataReaderCore.InterceptExceptionAsync[T](Func2 action)\r\n at Microsoft.AspNetCore.OData.Formatter.Wrapper.ODataReaderExtensions.ReadResourceOrResourceSetAsync(ODataReader reader) in C:\\github\\AspNetCoreOData\\src\\Microsoft.AspNetCore.OData\\Formatter\\Wrapper\\ODataReaderExtensions.cs:line 60\r\n at Microsoft.AspNetCore.OData.Formatter.Deserialization.ODataResourceDeserializer.ReadAsync(ODataMessageReader messageReader, Type type, ODataDeserializerContext readContext) in C:\\github\\AspNetCoreOData\\src\\Microsoft.AspNetCore.OData\\Formatter\\Deserialization\\ODataResourceDeserializer.cs:line 90\r\n at Microsoft.AspNetCore.OData.Formatter.ODataInputFormatter.ReadFromStreamAsync(Type type, Object defaultValue, Uri baseAddress, ODataVersion version, HttpRequest request, IList1 disposes) in C:\github\AspNetCoreOData\src\Microsoft.AspNetCore.OData\Formatter\ODataInputFormatter.cs:line 219\r\n at Microsoft.AspNetCore.OData.Formatter.ODataInputFormatter.LoggerError(HttpContext context, Exception ex) in C:\github\AspNetCoreOData\src\Microsoft.AspNetCore.OData\Formatter\ODataInputFormatter.cs:line 249\r\n at Microsoft.AspNetCore.OData.Formatter.ODataInputFormatter.ReadFromStreamAsync(Type type, Object defaultValue, Uri baseAddress, ODataVersion version, HttpRequest request, IList`1 disposes) in C:\github\AspNetCoreOData\src\Microsoft.AspNetCore.OData\Formatter\ODataInputFormatter.cs:line 223\r\n at Microsoft.AspNetCore.OData.Formatter.ODataInputFormatter.ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding) in C:\github\AspNetCoreOData\src\Microsoft.AspNetCore.OData\Formatter\ODataInputFormatter.cs:line 135"

corranrogue9 avatar Nov 07 '23 18:11 corranrogue9

This works:

{
    "@context":"#$delta"
    "ProductOrders@delta": [
        {
            "@removed": {
                "reason": "deleted"
            },
            "id": "1"
        }
    ]
}

The problem comes in when we add @odata.type :


{
    "@context":"#$delta"
    "ProductOrders@delta": [
        {
            "@odata.type": "ODataPerformanceProfile.Models.Order",
            "@removed": {
                "reason": "deleted"
            },
            "id": "1"
        }
    ]
}

ElizabethOkerio avatar Nov 14 '23 14:11 ElizabethOkerio

This isn't actually a workaround for the repro given. See this issue, which demonstrates that the @odata.type is required by WebApi and the standard for cases where the collection is of an abstract type.

The problem does come in when the @odata.type is added, and that is the entire bug. There should not be a problem when the @odata.type is added because it is a required JSON property for this request payload.

corranrogue9 avatar Aug 05 '24 16:08 corranrogue9

True. This was a report of the findings and not a workaround.

ElizabethOkerio avatar Aug 05 '24 19:08 ElizabethOkerio