I am trying to take this API and generalize Pagination, so it can be used for Any of my APIs and Models. How would I conduct this? I placed existing code base below, and want to have applicable to all apis and their getmethods. Researching to modify this function. If Microsoft has built into functionality to support this, I am open to Any other strategies.
From Resource (Existing Code only used can be used for 1 Class API):
https://dejanstojanovic.net/aspnet/2019/january/filtering-and-paging-in-aspnet-core-web-api/
Background:
We prepared many Get APIs, and now want pagination support for all 200+ apis. (I came into the project later) Without manually update/recoding everything, is there a automatic method to apply routing/pagination to all APIs for our end point customers using maybe resource link above or other ideas? Seeking way to filter all APIs.
public ActionResult<PagedCollectionResponse<Person>> Get([FromQuery] SampleFilterModel filter)
/api/Persons?Page=2&Limit=3
/api/Inventory?Page=2&Limit=3
/api/Product?Page=2&Limit=3
/api/Product/GetAll/Page=2&Limit=4
/api/Product/GetByProductCategory/7/Page=2&Limit=4
/api/Product/GetByVendorId/2/Page=2&Limit=4
/api/Product/GetByProductLocation/US/CA/Page=2&Limit=4
Code:
namespace Sample.Web.Api.Models
{
public abstract class FilterModelBase:ICloneable
{
public int Page { get; set; }
public int Limit { get; set; }
public FilterModelBase()
{
this.Page = 1;
this.Limit = 100;
}
public abstract object Clone();
}
}
public class SampleFilterModel:FilterModelBase
{
public string Term { get; set; }
public SampleFilterModel():base()
{
this.Limit = 3;
}
public override object Clone()
{
var jsonString = JsonConvert.SerializeObject(this);
return JsonConvert.DeserializeObject(jsonString,this.GetType());
}
}
namespace Sample.Web.Api.Models
{
public class PagedCollectionResponse<T> where T:class
{
public IEnumerable<T> Items { get; set; }
public Uri NextPage { get; set; }
public Uri PreviousPage { get; set; }
}
}
namespace Sample.Web.Api.Models
{
public class Person
{
public String Name { get; set; }
public DateTime DOB { get; set; }
public String Email { get; set; }
}
}
namespace Sample.Web.Api.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class PersonsController : ControllerBase
{
IEnumerable<Person> persons = new List<Person>() {
new Person() { Name = "Nancy Davolio", DOB = DateTime.Parse("1948-12-08"), Email = "nancy.davolio@test.com" },
new Person() { Name = "Andrew Fuller", DOB = DateTime.Parse("1952-02-19"), Email = "andrew.fuller@test.com" },
new Person() { Name = "Janet Leverling", DOB = DateTime.Parse("1963-08-30"), Email = "janet.leverling@test.com" },
new Person() { Name = "Margaret Peacock", DOB = DateTime.Parse("1937-09-19"), Email = "margaret.peacock@test.com" },
new Person() { Name = "Steven Buchanan", DOB = DateTime.Parse("1955-03-04"), Email = "steven.buchanan@test.com" },
new Person() { Name = "Michael Suyama", DOB = DateTime.Parse("1963-07-02"), Email = "michael.suyama@test.com" },
new Person() { Name = "Robert King", DOB = DateTime.Parse("1960-05-29"), Email = "robert.king@test.com" },
new Person() { Name = "Laura Callahan", DOB = DateTime.Parse("1958-01-09"), Email = "laura.callahan@test.com" },
new Person() { Name = "Anne Dodsworth", DOB = DateTime.Parse("1966-01-27"), Email = "anne.dodsworth@test.com" }
};
// GET api/values
[HttpGet]
public ActionResult<PagedCollectionResponse<Person>> Get([FromQuery] SampleFilterModel filter)
{
//Filtering logic
Func<SampleFilterModel, IEnumerable<Person>> filterData = (filterModel) =>
{
return persons.Where(p => p.Name.StartsWith(filterModel.Term ?? String.Empty, StringComparison.InvariantCultureIgnoreCase))
.Skip((filterModel.Page-1) * filter.Limit)
.Take(filterModel.Limit);
};
//Get the data for the current page
var result = new PagedCollectionResponse<Person>();
result.Items = filterData(filter);
//Get next page URL string
SampleFilterModel nextFilter = filter.Clone() as SampleFilterModel;
nextFilter.Page += 1;
String nextUrl = filterData(nextFilter).Count() <= 0 ? null : this.Url.Action("Get", null, nextFilter, Request.Scheme);
//Get previous page URL string
SampleFilterModel previousFilter = filter.Clone() as SampleFilterModel;
previousFilter.Page -= 1;
String previousUrl = previousFilter.Page <= 0 ? null : this.Url.Action("Get", null, previousFilter, Request.Scheme);
result.NextPage = !String.IsNullOrWhiteSpace(nextUrl) ? new Uri(nextUrl) : null;
result.PreviousPage = !String.IsNullOrWhiteSpace(previousUrl) ? new Uri(previousUrl) : null;
return result;
}
}
}
Note:
Need to Extend it to the API level as per resource. We know it can be done in business repository method, but want to generalize for all Controller APIs like author from above .