OData / WebApi

OData Web API: A server library built upon ODataLib and WebApi
https://docs.microsoft.com/odata
Other
856 stars 473 forks source link

Can't serialize properly using a Custom ResourceSerializer #2857

Open aramosvizcarra opened 3 days ago

aramosvizcarra commented 3 days ago

I created a custom OData Resource Serializer as part of the migration into dotnet core 8 and OData 9 This was mainly to maintain out previous syntax and suppor Geometry type from SQL spatial and NTS. This works fine as long as we don't use $select or $expand. As soon as I use them the serializer method WriteObjectInlineAsync graph object passes Microsoft.AspNetCore.OData.Query.Wrapper.SelectAll instead of NetTopologySuite.Geometries.Geometry and it doesn't seem possible to access the actual Geometry object from that. Although I'm fairly new to OData so I'm sure I'm missing something.

Assemblies affected

Microsoft.AspNetCore.OData

Reproduce steps

Custom ODataResourceSerializer.WriteObjectInlineAsync Select all records v/s $select or $expand

Expected result

Same custom data structure for Geometry values

Actual result

Different data structure since the serializer is using the default method WriteObjectInlineAsync since it can't cast the graph object type Microsoft.AspNetCore.OData.Query.Wrapper.SelectAll to NetTopologySuite.Geometries.Geometry

Additional detail

public override async Task WriteObjectInlineAsync(
object graph,
IEdmTypeReference expectedType,
ODataWriter writer,
ODataSerializerContext writeContext)
{
    try
    {        
        if (graph is NetTopologySuite.Geometries.Geometry geometry) <-----HERE when using $select or $expand I see Microsoft.AspNetCore.OData.Query.Wrapper.SelectAll<NetTopologySuite.Geometries.Geometry> not NetTopologySuite.Geometries.Geometry and there are no available methods to retrieve the geometry instance
        {
            // Handle the serialization of the Geometry type here
            var serializedGeometry = geometry.SerializeGeomerty();
            await writer.WriteStartAsync(serializedGeometry);
            await writer.WriteEndAsync();
        }
        else
        {
            // Fallback to the default behavior
            await base.WriteObjectInlineAsync(graph, expectedType, writer, writeContext);
        }
    }
    catch (Exception ex)
    {
        // Log any exceptions for further inspection
        Console.WriteLine($"Error during serialization: {ex.Message}");
        throw;
    }
}
xuzhg commented 21 hours ago

@aramosvizcarra If you have $select and $expand, the result as SelectAll<T> or similar is expected.

For your scenario, I think you can 1) create a 'ResourceContext' and use it to retrieve the ObjectInstance 2) cast graph to ISelectExpandWrapper and use it to retrieve its all properties.