AspNetCoreOData
AspNetCoreOData copied to clipboard
OData server crashes when trying to update (PATCH) a property of type NTSTopology.Geometry.Point
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 ?
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).
I have replied the error on https://github.com/OData/WebApi/issues/2271#issuecomment-763624013
@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/
Another blog post that may assist https://devblogs.microsoft.com/odata/customizing-filter-for-spatial-data-in-asp-net-core-odata-8/