Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using NetTopologySuite.Io.GeoJSON4STJ with FluentValidation throws ArgumentOutOfRangeException #109

Open
jeroenwo opened this issue Aug 28, 2022 · 7 comments

Comments

@jeroenwo
Copy link

Good morning,

I am using NetTopologySuite.Io.GeoJSON4STJ in combination with FluentValidation, and when I try to do a POST to an endpoint with for example an IFeature with Polygon data, I get the following exception:

System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. (Parameter 'X called on empty Point')
at NetTopologySuite.Geometries.Point.get_X()

I have narrowed it down to thFluentValidation initialization:

  • When it is present, the problem occurs
  • Without it, it works fine (Unfortunately it is a functionality which we use extensively, so removing it is not an option)
  • When POSTing a Point, it works fine
  • When POSTing a Polygon, the problem occurs

Reproduction:

  1. Use the example vor from
  2. Add <PackageReference Include="FluentValidation.AspNetCore" Version="10.3.3" />
  3. Add the following line in Program.cs: builder.Services.AddFluentValidation();
  4. Create a POST that accepts an IFeature
  5. Set a breakpoint in the controller method
  6. Run the project
  7. Run Swagger
  8. POST a Polygon

Here is an example of the project I use:
TestGeoJsonWebApi.zip

The complete stack trace:

System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. (Parameter 'X called on empty Point')
at NetTopologySuite.Geometries.Point.get_X()
at Microsoft.Extensions.Internal.PropertyHelper.CallNullSafePropertyGetter[TDeclaringType,TValue](Func2 getter, Object target) at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.DefaultComplexObjectValidationStrategy.Enumerator.<>c__DisplayClass13_1.<MoveNext>b__1() at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationEntry.get_Model() at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitChildren(IValidationStrategy strategy) at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitComplexType(IValidationStrategy defaultStrategy) at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitImplementation(ModelMetadata& metadata, String& key, Object model) at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.Visit(ModelMetadata metadata, String key, Object model) at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitChildren(IValidationStrategy strategy) at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitComplexType(IValidationStrategy defaultStrategy) at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitImplementation(ModelMetadata& metadata, String& key, Object model) at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.Visit(ModelMetadata metadata, String key, Object model) at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitChildren(IValidationStrategy strategy) at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitComplexType(IValidationStrategy defaultStrategy) at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitImplementation(ModelMetadata& metadata, String& key, Object model) at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.Visit(ModelMetadata metadata, String key, Object model) at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitChildren(IValidationStrategy strategy) at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitComplexType(IValidationStrategy defaultStrategy) at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitImplementation(ModelMetadata& metadata, String& key, Object model) at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.Visit(ModelMetadata metadata, String key, Object model) at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitChildren(IValidationStrategy strategy) at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitComplexType(IValidationStrategy defaultStrategy) at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.VisitImplementation(ModelMetadata& metadata, String& key, Object model) at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.Visit(ModelMetadata metadata, String key, Object model) at Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.Validate(ModelMetadata metadata, String key, Object model, Boolean alwaysValidateAtTopLevel, Object container) at FluentValidation.AspNetCore.FluentValidationVisitor.<>n__1(ModelMetadata metadata, String key, Object model, Boolean alwaysValidateAtTopLevel, Object container) at FluentValidation.AspNetCore.FluentValidationVisitor.<>c__DisplayClass2_0.<Validate>g__BaseValidate|0() in /media/jskinner/Linux2/code/FluentValidation/src/FluentValidation.AspNetCore/FluentValidationVisitor.cs:line 44 at FluentValidation.AspNetCore.FluentValidationVisitor.ValidateInternal(ModelMetadata metadata, String key, Object model, Func1 continuation) in /media/jskinner/Linux2/code/FluentValidation/src/FluentValidation.AspNetCore/FluentValidationVisitor.cs:line 62
at FluentValidation.AspNetCore.FluentValidationVisitor.Validate(ModelMetadata metadata, String key, Object model, Boolean alwaysValidateAtTopLevel, Object container) in /media/jskinner/Linux2/code/FluentValidation/src/FluentValidation.AspNetCore/FluentValidationVisitor.cs:line 46
at Microsoft.AspNetCore.Mvc.ModelBinding.ObjectModelValidator.Validate(ActionContext actionContext, ValidationStateDictionary validationState, String prefix, Object model, ModelMetadata metadata, Object container)
at Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.EnforceBindRequiredAndValidate(ObjectModelValidator baseObjectValidator, ActionContext actionContext, ParameterDescriptor parameter, ModelMetadata metadata, ModelBindingContext modelBindingContext, ModelBindingResult modelBindingResult, Object container)
at Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionContext actionContext, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor parameter, ModelMetadata metadata, Object value, Object container)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.<>c__DisplayClass0_0.<g__Bind|0>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

I know it isn't a purely NTS problem but more an integration thing, but I was wondering if you can shed some light on it..

@airbreather
Copy link
Member

Very related to #68

@jeroenwo
Copy link
Author

That issue was openend in 2020 and isn't closed yet. Does that mean that all hope is lost (in my case ;)? Without FV, everything seems to be in working order..

@FObermaier
Copy link
Member

Would it be sufficient to avoid throwing exceptions on properties? If so, that can be discussed, I think.

@airbreather
Copy link
Member

I think changing the property getters not to throw is a good idea regardless. Perhaps return double.NaN.

That said, ultimately, if your model contains an object that's serialized using our GeoJSON stuff and you use Swashbuckle or a similar tool to auto-generate the spec for it by reflecting over the CLR model instead of using that same GeoJSON stuff, then you're going to get an incorrect result. Changing a few property getters to stop throwing errors won't fix that.

@jeroenwo
Copy link
Author

jeroenwo commented Sep 1, 2022

As a workaround, I have removed builder.Services.AddFluentValidation();. Since I am not using FV in the web API for model validation but more downstream, I was able to inject them using builder.Services.AddValidatorsFromAssemblyContaining<MyCustomValidator>(); and retrieving it via the IServiceProvider.

I can use NTS.IO.GeoJSON4STJ now..

@shanerogers
Copy link

shanerogers commented Feb 9, 2023

@jeroenwo we also discovered this issue yesterday.. sigh. This really does need fixing.
Luckily we also do not use fluent validation in our asp.net pipeline. Our fluent validation occurs in our queries/commands.
How can we get the Point and other objects to not throw an exception on {get} I wonder if the nullable changes 'required' keywords for C# can be used and would help...?

@Atomosk
Copy link

Atomosk commented Jul 7, 2023

As a workaround you can add the FluentValidation.AspNetCore nuget and use the [ValidateNever] attribute on a Geometry property.

FObermaier added a commit to NetTopologySuite/NetTopologySuite that referenced this issue Sep 15, 2023
...  to not throw ArgumentOutOfRangeException.
* Instead double.NaN is returned.
* The setters don't perform any operation.

refers to NetTopologySuite/NetTopologySuite.IO.GeoJSON/issues/109
FObermaier added a commit to NetTopologySuite/NetTopologySuite that referenced this issue Sep 15, 2023
* Instead double.NaN is returned.
* The setters don't perform any operation.

refers to NetTopologySuite/NetTopologySuite.IO.GeoJSON/issues/109
airbreather added a commit to NetTopologySuite/NetTopologySuite that referenced this issue Mar 12, 2025
This includes everything added to JTS 1.20.0. For details, see the JTS release documentation for this version: https://github.com/locationtech/jts/releases/tag/1.20.0

Other changes include:

1. `NetTopologySuite.Geometries.Utilities.Extracter`, which includes our own strongly-typed spin on the other extracters found in this namespace.
2. #685 / #686: Better handling of `srsDimension` when reading GML.
3. Start taking advantage of some more modern .NET SDK features. (Don't worry, .NET Standard 2.0 is still fully supported.)
4. #702 / #703: `NetTopologySuite.Geometries.GeometryCollection` now implements `System.Collections.Generic.IReadOnlyList<Geometry>`.
5. #712 / (related to) NetTopologySuite/NetTopologySuite.IO.GeoJSON#109: Certain property getters no longer throw exceptions. Very softly related to: locationtech/jts#434 (comment)
6. #733: *some* help converting between tuples and coordinates
7. #738: minor documentation fix
8. #745 / #746: Add a .NET Standard 2.1 target so that the majority of modern applications no longer need to deal with a transient `System.Memory` package reference.
9. #751: .NET-specific (mostly) performance improvement for most queries using `NetTopologySuite.Index.Strtree` indexes.
10. #765 / #655 / #656 / locationtech/jts#714: Deviate from JTS a little bit in an attempt to soften a regression related to elevation that was introduced by OverlayNG. See linked issues for history, discussion, and more.
11. Bump `System.Memory` package reference to 4.6.0 so that .NET Standard 2.0 consumers debugging into this will see a link to the currently maintained version of this "slow span" package.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants