'Generic Types for Paginated Repsonse
I'm working on a .NET Core application that utilizes EventBrite's API. Within the EventBrite API, many result sets are paginated. My use case requires me to retrieve the full results for multiple sets of data - Events, Attendees, etc.
Rather than have the same logic to handle each Paginated result set, I figured I could create a generic method to loop through the paginated results and get my results back - something like the following.
private List<T> GetPaginatedResult<T>(string path) where T : class
{
var firstResult = GetEventBriteResult<PaginatedResponse<T>>(path);
var pages = firstResult.Pagination.page_count;
var results = firstResult.Objects;
if (pages > 1)
{
for (int i = 1; i < pages; i++)
{
var paginatedPath = path + $"?page={i + 1}";
var paginatedResult = GetEventBriteResult<PaginatedResponse<T>>(paginatedPath);
results.AddRange(paginatedResult.Objects);
}
}
return results;
}
Each of the EventBrite result sets contains a 'Pagination' object, as well as the list of the current pages datasets.
I created a class to handle the Paginated results, where the EventBritePagination class matches the EventBrite class to handle pagination. The Objects property is where I'm having issues.
public class PaginatedResponse<T> where T : class
{
public EventBritePagination Pagination { get; set; } = new EventBritePagination();
public virtual List<T> Objects { get; set; } = new List<T>();
}
The issue is that EventBrite has custom naming conventions for each of their classes. For example, looking at the 'Event' class and the 'Attendee' class, they would look like the following if I had built them out manually.
public class EventBriteEvent {
EventBritePagination Pagination { get; set; }
List<Event> Events { get; set; }
}
public class EventBriteAttendee {
EventBritePagination Pagination { get; set; }
List<Attendee> Attendees { get; set; }
}
Each class has the 'Pagination' object, but the Properties I'm attempting to map to the list of 'Objects' has a different name for each object type.
So when I go to deserialize the response, I end up needing to define multiple JsonPropertyNames in order to facilitate the fact that my Objects property may be named 'attendees' or 'events' or similar.
I know there's got to be a better way to do this with Generic types, but they aren't my strong suit.
Is there a way that I can define a class with a Generic property that can deserialize from a variety of JsonPropertyNames? Or a way to achieve the end goal with another method of inheritance?
Edit 1
For abundance of clarity, this is what the actual JSON response from EventBrite looks like.
First, the result for Attendees
{
"pagination": {
"page_number": 1,
"page_count": 1
},
"attendees": [
{ "first" : "Jeff", ... },
{ "first" : "John", ... }
]
And secondly, the Events...
{
"pagination": {
"page_number": 1,
"page_count": 1
},
"events": [
{ "name" : "Anime NebrasKon 2014", ... },
{ "name" : "Anime NebrasKon 2015", ... }
]
Both responses contain the 'Pagination' property, but differing second attributes. The second attribute will always be a List of objects, however.
My goal is to build a reusable method where I can grab either the Attendees or the Events (or any of the paginated results from EventBrite)
The biggest issue is that because the secondary attributes are named differently, I can't reference the specific secondary attribute that I need to - and if I keep it generic, as a List<T> Objects, then I can't deserialize the Objects list using JsonPropertyNames, as I can only specify one name, not multiple.
Solution 1:[1]
You can use a property selector Func like so to pass in the property that you want to use.
public static PaginatedResponse<ResultType> ResponseFactory<ResponseType, ResultType>(ResponseType response, Func<ResponseType, List<ResultType>> selector)
{
var pagResp = new PaginatedResponse<ResultType>();
// use the selector to map the list from the response to objects
pagResp.Objects = selector(response);
return pagResp;
}
You would call the above like so:
var response = ResponseFactory<EventBriteEvent, Event>(apiReponse, x => x.Events);
You will have to modify this example to incorporate into your GetPaginatedResult function, but this should get you moving in the right direction. I opted to keep the example separate to help the concept stand out.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | John Glenn |
