OData / AspNetCoreOData

ASP.NET Core OData: A server library built upon ODataLib and ASP.NET Core
Other
454 stars 159 forks source link

OData version error when requesting 4.01 bulk update #1261

Open AlpineJBoehnen opened 3 months ago

AlpineJBoehnen commented 3 months ago

Assemblies affected

Describe the bug Related issue: https://github.com/OData/odata.net/issues/3004

My primary question is: does Microsoft.AspNetCore.OData support the OData 4.01 spec, specifically bulk update operations?

When the client sends a bulk update request with the OData-Version header set to 4.01 the library throws the exception An OData version of 4.01 was specified and the maximum supported OData version is 4.0., then continues to the controller action with the DeltaSet<T> parameter as null. If I send an identical request from postman with the header set to 4.0 instead, the library seemingly has no issue and populates the DeltaSet<T> as expected (for a simple model without related entities or links).

Reproduce steps I implemented Sample Request 1 from the OData Client Bulk Update Operations examples on my client. And implemented an endpoint on my server to "patch a collection of entities" from this Microsoft.AspNetCore.OData tutorial.

Note: I modified the client example to work with the Shape model from the server example.

Client code:

Default.Container context = new Default.Container(new Uri("https://localhost:7092/odata/"), Microsoft.OData.Client.ODataProtocolVersion.V4);

Shape s1 = new Shape { Id = 1, Area = 10 };
context.AddToShapes(s1);

Shape s2 = new Shape { Id = 2, Area = 20 };
context.AddToShapes(s2);

context.BulkUpdate(s1, s2);

Server code:

// Program.cs
var builder = WebApplication.CreateBuilder(args);
var modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<Shape>("Shapes");

builder.Services.AddControllers()
    .AddOData(opts =>
    {
        opts.EnableQueryFeatures().AddRouteComponents("odata", modelBuilder.GetEdmModel());
    });
// ShapesController.cs
public class ShapesController : ODataController
{
    private static List<Shape> shapes = new List<Shape>
    {
        new Shape { Id = 1, Area = 28 },
        new Shape { Id = 2, Area = 38.5 },
        new Shape { Id = 3, Area = 40 }
    };

    public async Task<ActionResult> Patch([FromBody] DeltaSet<Shape> deltaSet)
    {
        if (deltaSet == null)
        {
            return BadRequest();
        }

        return Ok();
    }
}

Data Model

/// Shape.cs
public class Shape
{
    public int Id { get; set; }
    public double Area { get; set; }
}

EDM (CSDL) Model

<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
  <edmx:DataServices>
    <Schema Namespace="ODataSandboxApi.Models" xmlns="http://docs.oasis-open.org/odata/ns/edm">
      <EntityType Name="Shape">
        <Key>
          <PropertyRef Name="Id" />
        </Key>
        <Property Name="Id" Type="Edm.Int32" Nullable="false" />
        <Property Name="Area" Type="Edm.Double" Nullable="false" />
      </EntityType>
    </Schema>
    <Schema Namespace="Default" xmlns="http://docs.oasis-open.org/odata/ns/edm">
      <EntityContainer Name="Container">
        <EntitySet Name="Shapes" EntityType="ODataSandboxApi.Models.Shape" />
      </EntityContainer>
    </Schema>
  </edmx:DataServices>
</edmx:Edmx>

Request/Response

PATCH https://localhost:7092/odata/Shapes:

{
  "@context": "https://localhost:7092/odata/$metadata#Shapes/$delta",
  "value": [
    {
      "Area": 10.0,
      "Id": 1
    },
    {
      "Area": 20.0,
      "Id": 2
    }
  ]
}

Accept:             application/json; odata.metadata=minimal
Host:               localhost:7092
User-Agent:         Microsoft.OData.Client/8.0.0
Accept-Charset:     UTF-8
Content-Type:       application/json; odata.metadata=minimal
Content-Length:     119
OData-MaxVersion:   4.01
OData-Version:      4.01

Expected behavior A clear and concise description of what you expected to happen.

Screenshots If applicable, add screenshots to help explain your problem.

Additional context Exception:

Microsoft.OData.ODataException
  HResult=0x80131509
  Message=An OData version of 4.01 was specified and the maximum supported OData version is 4.0.
  Source=Microsoft.OData.Core
  StackTrace:
   at Microsoft.OData.ODataMessageReader..ctor(IODataRequestMessage requestMessage, ODataMessageReaderSettings settings, IEdmModel model)
habbes commented 3 months ago

@AlpineJBoehnen this blog post demonstrates how to use bulk ops on the server with Microsoft.AspNetCore.OData https://devblogs.microsoft.com/odata/bulk-operations-support-in-odata-web-api/, the blog post is based on the 7.x version, but it should work for 8 as well (@ElizabethOkerio correct me if I'm wrong)