In this article, we’re going to talk about sorting in ASP.NET Core Web API. Sorting is a commonly used mechanism, that every API should implement. Implementing it in ASP.NET Core is not difficult due to the flexibility of LINQ and good integration with EF Core.

If you want to follow along with the article, you can use the start branch and if you want to get the final solution or if you get stuck, switch to the final branch.

NOTE: Some degree of previous knowledge is needed to follow this article. It relies heavily on the ASP.NET Core Web API series on Code Maze, so if you are not sure how to set up the database or how the underlying architecture works, we strongly suggest you go through the series.

In this article we are going to learn:

Let’s begin.

What is Sorting?

Sorting, in this case, refers to ordering our results in a preferred way, using our query string parameters. We are not talking about sorting algorithms nor we are going into how’s of implementing a sorting algorithm.

What we’re interested in, however, is how do we make our API sort our results the way we want it to.

Let’s say we want our API to sort owners by their name in ascending order, and then by their date of birth.

To do that, our API call needs to look something like this:

https://localhost:5001/api/owner?orderBy=name,dateOfBirth desc

Our API needs to take all the parameters into consideration and sort our results accordingly. In our case, this means sorting results by their name, and then, if there are owners with the same name, sorting them by the DateOfBirth property.

Let’s recall how our owner data looks like in the database:

database owners

For the sake of demonstrating this example, we are going to add one more Anna Bosh to our database. You can add whatever you want besides that to test the results.

So, let’s add another Anna Bosh:

database owners extended

The new Anna is 10 years older and lives on a different address.

Great, now we have the required data to test our functionality properly.

And of course, like with all other functionalities we’ve implemented so far (paging, filtering, and searching), we need to implement this to work well with everything else. We should be able to get the paginated, filtered and sorted data for example.

Let’s see one way to go around implementing this.

How to Implement Sorting in ASP.NET Core Web API

First, since we want every Entity to be sortable by some criterium, we are going to add OrderBy property to our base class QueryStringParameters:

We won’t set any default values since different classes can have different default values.

For example, we want OwnerParameters to order our results by the property “name” by default:

And we want our Accounts to be ordered by DateCreated:

Next, we’re going to dive right into the implementation of our sorting mechanism, or rather, our ordering mechanism.

One thing to note is that we’ll be using System.Linq.Dynamic.Core NuGet package to dynamically create our OrderBy query on the fly. So, feel free to install it in the Repository project and add a using directive in the OwnerRepository class.

Let’s add a new private method ApplySort in our OwnerRepository class:

Okay, that’s one big ass method. We’re actually doing multiple different things here to get our results sorted, so let’s take it step-by-step and see what’ve done exactly.

Let’s dissect our method.

Implementation – Step by Step

First, let start with the method definition. It has two arguments, one for the list of owners as IQueryable<Owner>, and other for the ordering query. If we send a request like this one https://localhost:5001/api/owner?orderBy=name,dateOfBirth desc, our orderByQueryString will be name,dateOfBirth desc.

We begin our method implementation with some mandatory checks for owners and queryString. If there are no owners, we exit the method immediately. If we’ve got some owners, but the query string is empty, we want to order the owners by name:

Next, we’re splitting our query string to get the individual fields:

We’re also using a bit of reflection to prepare the list of PropertyInfo objects that represent the properties of our Owner class. We need them to be able to check if the field received through the query string really exists in the Owner class:

Having that prepared, we can actually run through all the parameters and check for their existence:

If we don’t find such a property we skip the step in the foreach loop and go to the next parameter in the list:

If we do find the property, we return it and additionally check if our parameter contains “desc” at the end of the string. We use that to decide how we should order our property:

We use the StringBuilder to build our query with each loop:

Now that we’ve looped through all the fields, we are removing excess commas and doing one last check to see if our query indeed has something in it:

Finally, we can order our query:

At this point, our orderQuery variable should contain “Name ascending, DateOfBirth descending” string. That means it will order our results first by Name in ascending order, and then by DateOfBirth in descending order.

The standard LINQ query for this would be:

A neat little trick to form a query when you don’t know how you should sort in advance.

Calling the Method

Now that we’ve seen how the method works up close, we should just call it in our GetOwners method:

We are providing the list of owners and the OrderBy query string.

That’s it for our implementation. Or maybe not? What if we want to use ApplySort in the AccountRepository? Should we actually keep this logic in our repository class?

The answer to both our questions is of course NO!

Let’s see how to make our method more generic, and implement it in such a way that it can be used by both Account and Owner repositories (or any other repository that comes later).

Improving the Solution

There are two main things we want to improve on. Kick the private ApplySort method out of the OwnerRepository, and make the ApplySort generic.

So let’s start by defining the SortHelper class and the ISortHelper interface in the Helpers folder of the Entities project.

ISortHelper should declare one method – ApplySort:

As you can see, ISortHelper is a generic interface and it can be applied to any type we want. We need to provide a collection of entities, and a sorting string.

Now let’s see the actual implementation:

This implementation gives us the ability to inject this class to our repositories and call ApplySort wherever we need it:

We also need to extend our RepoWrapper since our repository classes are instantiated there:

And now we can call it in our GetOwners method:

Same thing with the AccountRepository. If you are having trouble implementing it, refer to the finished project on GitHub at the top of the article.

And since we used dependency injection to inject our SortHelper, we need to not forget to register it in our ServiceExtensions class:

A lot of work, but it’s worth it, now we can apply sorting to any entity in our project, even if we add new ones in the future.

Let’s test it out.

Testing Our Implementation

Now the fun part starts, let’s put the result of all our efforts to test.

First, let’s try out the query we’ve been using as an example:
https://localhost:5001/api/owner?orderBy=name,dateOfBirth desc

The response should be:

As you can see, the list is sorted by Name ascending, and since we have two Anna’s, they were sorted by DateOfBirth, descending.

Now try reversing the ordering in the query:
https://localhost:5001/api/owner?orderBy=name desc,dateOfBirth

Now the result should be:

Works like a charm!

Now, you can try different invalid queries like:
https://localhost:5001/api/owner?orderBy=age
https://localhost:5001/api/owner?orderBy= 
https://localhost:5001/api/owner?orderBy=name desc&dateOfBirth

and see the results for yourself.

One more thing we should try is if the solution works when combined with paging, filtering and searching.

https://localhost:5001/api/owner?pageNumber=1&pageSize=5&orderBy=dateOfBirth asc&minYearOfBirth=1960&maxYearOfBirth=1980&name=Anna

Can you guess what’s the result of this query? If you’ve guessed, leave us a comment with what you think the result is.

That’s it, let’s summarize.

Conclusion

As you have seen, even the trivial sort like this requires a certain amount of business logic, some reflection, validation and even a bit of dynamic query building. But once you implement it, your API becomes really versatile and flexible.

This implementation is as simple as it gets, but there are certain things we can do to improve it. We can implement a service layer (we don’t have one to keep things simple), we can make our code generic, and not just owner-specific, and we can, of course, create an extension method ApplySort for IQueryable which would make this solution even more flexible.

In this article we’ve covered:

  • The definition of sorting and how it works
  • One way to implement sorting in ASP.NET Core Web API
  • Testing our solution for valid and invalid queries
  • Testing if our solution works together with paging, filtering and searching

That’s it for sorting. If you have any questions or suggestions, please leave us a comment.

Next up, we’ll cover a very nice topic of data shaping.