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

Pageable is trying to create the "Previous" property when page is 0 #18

Open
venturialberto opened this issue Aug 14, 2023 · 0 comments

Comments

@venturialberto
Copy link
Contributor

Overview of the issue

Hi,
I would like to share an issue I have faced while using the library.

I was trying to copy the configuration of the backend pagination, used on another project.
I created a new .net 6 web api, imported the JHipsterNet.Core and JHipsterNet.Web 1.0.9, created an endpoint with a IPageable as parameter and a custom object with the annotation [FromQuery], but it seems to not work.

In the working project i was able to call the api without specifing a single parameter.

This was the stack trace:

System.ArgumentNullException: Page Number must not be less than zero! (Parameter 'pageNumber')
   at JHipsterNet.Core.Pagination.Pageable..ctor(Int32 pageNumber, Int32 pageSize, Sort sort) in ...path...JHipsterNet.Core\Pagination\Pageable.cs:line 8
   at JHipsterNet.Core.Pagination.Pageable.get_Previous() in ...path...\JHipsterNet.Core\Pagination\Pageable.cs:line 20
   at Microsoft.Extensions.Internal.PropertyHelper.CallNullSafePropertyGetter[TDeclaringType,TValue](Func`2 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.Validate(ModelMetadata metadata, String key, Object model, Boolean alwaysValidateAtTopLevel, Object container)
   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.<<CreateBinderDelegate>g__Bind|0>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   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)

HEADERS
=======
Accept: */*
Connection: keep-alive
Host: localhost:50001
User-Agent: PostmanRuntime/7.20.1
Accept-Encoding: gzip, deflate
Cache-Control: no-cache
Postman-Token: f9748320-c0cb-46a3-8966-05f0e44c6ce7

I found out the problem was on the constructor of the Pageable, precisely on the "Previous" property.

private Pageable(int pageNumber, int pageSize, Sort sort = null)
      {
          if (pageNumber < 0) {
              throw new ArgumentNullException(nameof(pageNumber), "Page Number must not be less than zero!");
          }

          if (pageSize < 1) {
              throw new ArgumentNullException(nameof(pageSize), "Page Size must not be less than one!");
          }

          PageNumber = pageNumber;
          PageSize = pageSize;
          Sort = sort ?? Sort.Unsorted;
      }

      public IPageable Previous => new Pageable(PageNumber - 1, PageSize, Sort);
      public bool IsPaged => true;

      public int PageNumber { get; }
      public int PageSize { get; }

      public int Offset => PageNumber * PageSize;
      public Sort Sort { get; }

      public IPageable Next => new Pageable(PageNumber + 1, PageSize, Sort);

      public IPageable PreviousOrFirst => HasPrevious ? Previous : First;

The only reference was on the "PreviousOrFirst".
The error was due to the Pageable with "page=0", trying to create the Pageable of the previous page, so "-1".

Solution
Later i found out the problem was on a property of the project that i had to remove.
https://learn.microsoft.com/en-us/dotnet/csharp/nullable-references#nullable-contexts

But i wanted to understand better the reasons of the exception.
So I debugged the JHipsterNet.Core and JHipsterNet.Web libraries and found out that the error was due to the "public" declaration of the variabile It seems that if it is public, at runtime the application is trying to resolve the "Previous" property even if it is not necessary (because the page is equal to 0).
In this way it is possibile to make the IPageable parameter optional and the custom object mandatory, without removing the null check project option (which is enable by default in the newest .net projects)

Reproduce the error

The project for testing is attached

Related issues
Suggest a Fix

Change the declaration of "Previous" from public to private.

JHipster Version(s)

1.0.9
JHipsterApiTest.zip

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

1 participant