OData / OData/AspNetCoreOData

Applying IfMatch when using a single DateTime as ETag gives an exception

Open
#948 2 comments 0 reactions 1 assignee View on GitHub

@habbes is already working on this.

Since Jun 6, 2023.

bug
Dominant language
C#
Stars
505
Forks
186
PR merge metrics
No merged PRs in 30d

Description

Assemblies affected
ASP.NET Core OData 8.2

Describe the bug
Using a DateTime property as ETag will throw the following exception when applying IfMatch.
"The binary operator Equal is not defined for the types 'System.DateTime' and 'System.DateTimeOffset'."

Reproduce steps
The simplest set of steps to reproduce the issue. If possible, reference a commit that demonstrates the issue.

Data Model

public class PieceDto {
    Guid id;
    string name;
    DateTime effectiveStart;
}

EDM (CSDL) Model
EDM model is defined using

        var builder = new ODataConventionModelBuilder();
        var piece = builder.EntitySet<PieceDto>(ODataRoutes.Pieces).EntityType;
        piece.Property(p => p.EffectiveStart).IsConcurrencyToken();

Request/Response
GET response will include a correct etag:

{
    "@odata.context": "https://localhost:5003/v1/$metadata#Pieces/$entity",
    "@odata.etag": "W/\"MjAyMi0xMi0yMFQyMDo0MzoyNy43Mzg1NDFa\"",
    "effectiveStart": "2022-12-20T20:43:27.738541Z",
    "id": "6a82a98d-d682-4bd9-a48e-0000094469c5",
}

But in patch method, when applying IfMatch, the exception is raised:

[ETagActionFilter]
public class PiecesODataController : ODataControllerBase
{
    [HttpPatch("{id}")]
    public async Task<IActionResult> Patch( [FromRoute] Guid id, ODataQueryOptions<PieceDto> options )
    {
        IQueryable<PieceDto> pieces = await _context.Piece.Where(x => x.Id == id)
            .GetQueryAsync(_mapper, options, CreateQuerySettings());

        if (pieces.IsEmpty())
        {
            return NotFound();
        }

        if (options.IfMatch == null)
        {
            return StatusCode(StatusCodes.Status412PreconditionFailed);
        }

        IQueryable<PieceDto> matchedPieces = options.IfMatch.ApplyTo(pieces).Cast<PieceDto>();
  
..... 
        }
}

In method DefaultODataEtagHandle.cs:ParseEtag the value retrieved from the etag iss parsed as DateTimeOffset (by ODataUriUtils.ConvertFromUriLiteral).

The exception is raised later when the Linq expression try to compare the original DateTime value to the DateTimeOffset retrieved.

Expected behavior
The value retrieved from the etag should have the same type than the original property used as ConcurrencyCheck.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.