Skip to content

V4 DynamoDb :: DbContext.QueryAsync<T> fails to deserialise List<T> #3871

Open
@alc-aardvark

Description

@alc-aardvark

Describe the bug

After upgrading my V3 code to V4, I am now getting the following failure.

Logged Exception

System.InvalidOperationException: Unable to convert DynamoDB entry [Amazon.DynamoDBv2.DocumentModel.DynamoDBList] of type Amazon.DynamoDBv2.DocumentModel.DynamoDBList to property Excesses of type System.Collections.Generic.List`1[[IQ.Car.Quote.CarQuoteExcess, IQ.Car.Quote, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
   at Amazon.DynamoDBv2.DataModel.DynamoDBContext.FromDynamoDBEntry(SimplePropertyStorage, DynamoDBEntry, DynamoDBFlatConfig) + 0x3a0
   at Amazon.DynamoDBv2.DataModel.DynamoDBContext.PopulateProperty(ItemStorage, DynamoDBFlatConfig, Document, String, PropertyStorage, Object) + 0x6e
   at Amazon.DynamoDBv2.DataModel.DynamoDBContext.PopulateInstance(ItemStorage, Object, DynamoDBFlatConfig, StorageConfig) + 0x1b5
   at Amazon.DynamoDBv2.DataModel.DynamoDBContext.DocumentToObject(Type, ItemStorage, DynamoDBFlatConfig) + 0xdd
   at Amazon.DynamoDBv2.DataModel.DynamoDBContext.FromDynamoDBEntry(SimplePropertyStorage, DynamoDBEntry, DynamoDBFlatConfig) + 0x268
   at Amazon.DynamoDBv2.DataModel.DynamoDBContext.PopulateProperty(ItemStorage, DynamoDBFlatConfig, Document, String, PropertyStorage, Object) + 0x6e
   at Amazon.DynamoDBv2.DataModel.DynamoDBContext.PopulateInstance(ItemStorage, Object, DynamoDBFlatConfig, StorageConfig) + 0x1b5
   at Amazon.DynamoDBv2.DataModel.DynamoDBContext.DocumentToObject(Type, ItemStorage, DynamoDBFlatConfig) + 0xdd
   at Amazon.DynamoDBv2.DataModel.DynamoDBContext.DocumentToObject[T](ItemStorage, DynamoDBFlatConfig) + 0x3a
   at Amazon.DynamoDBv2.DataModel.DynamoDBContext.<FromDocumentsHelper>d__65`1.MoveNext() + 0xa2
   at System.Collections.Generic.List`1..ctor(IEnumerable`1) + 0xf1
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1) + 0x43
   at Amazon.DynamoDBv2.DataModel.AsyncSearch`1.<GetRemainingAsync>d__23.MoveNext() + 0x155
--- End of stack trace from previous location ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x1c
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xbe
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x4e
   at IQ.Car.Quote.Database.DynamoDbQuotePersist.<QueryAsyncWithRetry>d__20`1.MoveNext() + 0x228

C# Code

                    CancellationTokenSource cts = new CancellationTokenSource(3 * 1000);
                    results = await DbContext.QueryAsync<T>(hashkey).GetRemainingAsync(cts.Token);

Class structure to be deserialised

     [DynamoDBTable("QuoteResponse")]
    public class QuoteResponse
    {
        public QuoteResponse()
        {
        }


        /// <summary>
        /// Quote Request Id
        /// </summary>
        [DynamoDBHashKey]
        public required string Id { get; init; } 

        /// <summary>
        /// Guid for Quote
        /// </summary>
        [DynamoDBRangeKey]
        public required string Insurer { get; init; }

        /// <summary>
        /// The row is considered "dead" on or after this time (Epoch time)
        ///  - Will be a short time after the expected next heartbeat time
        /// </summary>        
        [DynamoDBProperty("Live")]
        public long LiveTime { get; init; }


        /// <summary>
        /// Vehicle Registration Number
        /// </summary>
        [DynamoDBProperty("CarQuoteResponse")]
        public required CarQuoteResponse CarQuoteResponse { get; init; }
    }

    public class CarQuoteResponse
    {
        public string Insurer { get; set; } = string.Empty;
        public bool Successful { get; set; }
        public long ElapsedMs { get; set; }
        public decimal? TotalAnnual { get; set; }
        public string QuoteRef { get; set; } = string.Empty;
        public string QuoteRefUrl { get; set; } = string.Empty;
        public bool CanEmail { get; set; }
        public bool EmailSent { get; set; }
        public string? AddressText { get; set; }
        public string? VehicleDescription { get; set; }
        public List<CarQuoteExcess> Excesses { get; set; } = new List<CarQuoteExcess>();
        public string FailureReason { get; set; } = string.Empty;
        public bool CanDisplayFailure { get; set; }
}

    public class CarQuoteExcess
    {
        public string Description { get; set; } = string.Empty;
        public decimal? Excess { get; set; }
    }

Regression Issue

  • Select this option if this issue appears to be a regression.

Expected Behavior

I expect a list of 5 rows to be returned

Current Behavior

under the V4 code it throws an exception when deserialising the data from the dynamodb table. The data in the table looks to be persisted correctly.

Reproduction Steps

I would need to create this if required

Possible Solution

In the V3 code I included an rd.xml file as this is running on AWS Lambda using .Net 8 NativeAOT compilation

Additional Information/Context

Running as AWS Lambda using .Net 8 NativeAOT

AWS .NET SDK and/or Package version used

AWSSDK.Core (4.0.0.8)
AWSSDK.DynamoDBV2 (4.0.1.4)

Targeted .NET Platform

.NET 8 NativeAOT

Operating System and version

Amazon Linux

Metadata

Metadata

Assignees

No one assigned

    Labels

    aotAhead of TimebugThis issue is a bug.dynamodbp1This is a high priority issuepotential-regressionMarking this issue as a potential regression to be checked by team memberqueuedv4

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions