AspNetCoreOData icon indicating copy to clipboard operation
AspNetCoreOData copied to clipboard

OData server crashes when trying to update (PATCH) a property of type NTSTopology.Geometry.Point

Open fededim opened this issue 4 years ago • 4 comments
trafficstars

I am using Microsoft.AspNetCore.OData 7.5.2 on server and OData Connected Service 0.11.1 on client.

The client code tries to update a property on an Entity with type NTSTopology.Geometry.Point, the client performs the patch call but it crashes on server with this exception

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.MissingMethodException: No parameterless constructor defined for type 'NetTopologySuite.Geometries.Point'.
   at System.RuntimeType.CreateInstanceDefaultCtorSlow(Boolean publicOnly, Boolean wrapExceptions, Boolean fillCache)
   at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, Boolean wrapExceptions)
   at System.Activator.CreateInstance(Type type, Boolean nonPublic, Boolean wrapExceptions)
   at System.Activator.CreateInstance(Type type)
   at Microsoft.AspNet.OData.Delta`1.Reset(Type structuralType)
   at Microsoft.AspNet.OData.Delta`1..ctor(Type structuralType, IEnumerable`1 updatableProperties, PropertyInfo dynamicDictionaryPropertyInfo)
   at Microsoft.AspNet.OData.Delta`1..ctor(Type structuralType, IEnumerable`1 updatableProperties)
   --- End of inner exception stack trace ---
   at Microsoft.AspNet.OData.Formatter.ODataInputFormatter.<>c__DisplayClass7_0.<ReadRequestBodyAsync>b__1(Exception ex)
   at Microsoft.AspNet.OData.Formatter.ODataInputFormatterHelper.ReadFromStreamAsync(Type type, Object defaultValue, IEdmModel model, Uri baseAddress, IWebApiRequestMessage internalRequest, Func`1 getODataRequestMessage, Func`2 getEdmTypeDeserializer, Func`2 getODataPayloadDeserializer, Func`1 getODataDeserializerContext, Action`1 registerForDisposeAction, Action`1 logErrorAction)
   at Microsoft.AspNet.OData.Formatter.ODataInputFormatter.ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)

The client code is this:

            try
            {
                var ctx = new SincroADRODataService.Default.Container(new Uri("http://localhost/SincroADR_Api/odata"));
                var cam = new DataServiceCollection<Camera>(ctx.Cameras.Where(c => c.Id == 41)).SingleOrDefault();
                cam.Location.Y -= 0.2;
                ctx.SaveChanges();
            }
            catch (Exception ex)
            {
                log.LogError(ex, "error");
            }

The server patch method is this:

        [HttpPatch]
        public async Task<IActionResult> Patch([FromODataUri] Int64 key, Delta<Camera> c)
        {
            if (!ModelState.IsValid)
                return BadRequest(ModelState);

            var entity = await ctx.Set<Camera>().FindAsync(key);
            if (entity == null)
                return NotFound();

            c.Patch(entity);
            await ctx.SaveChangesAsync();
            return Updated(entity);
        }

I have no problem whatsoever in updating other properties. Any idea on how to solve this issue apart from adding the parameterless constructor to NTSTopology.Geometry.Point ?

fededim avatar Jan 14 '21 14:01 fededim

Just to be more precise, the API action does not "crash", instead returns bad request due to an invalid model state. If you inspect with the debugger the property ModelState.Root.Errors[0].Exception you find the above exception (it's the only one present).

fededim avatar Jan 14 '21 19:01 fededim

I have replied the error on https://github.com/OData/WebApi/issues/2271#issuecomment-763624013

Kasper888 avatar Jan 20 '21 14:01 Kasper888

@fededim

I saw the Point class definition here: https://github.com/NetTopologySuite/NetTopologySuite/blob/develop/src/NetTopologySuite/Geometries/Point.cs

This class doesn't have a default constructor and we can't instantize an object of "Point". Please use the POCO (a plain old CLR object, or plain old class object (POCO) ) class as the model type.

For a no-POCO, maybe need a converter. Here's a workaround that you might try it: https://devblogs.microsoft.com/odata/how-to-consume-sql-spatial-data-with-web-api-v2-2-for-odata-v4/

xuzhg avatar Jan 21 '21 20:01 xuzhg

Another blog post that may assist https://devblogs.microsoft.com/odata/customizing-filter-for-spatial-data-in-asp-net-core-odata-8/

KenitoInc avatar Apr 19 '22 06:04 KenitoInc