Problem
How to implement sorting in ASP.NET Core Web API.
Solution
Create an empty project, add NuGet package:
Update Startup
class to add services and middleware for MVC:
public void ConfigureServices(
IServiceCollection services)
{
services.AddSingleton<IMovieService, MovieService>();
services.AddMvc();
}
public void Configure(
IApplicationBuilder app,
IHostingEnvironment env)
{
app.UseDeveloperExceptionPage();
app.UseMvcWithDefaultRoute();
}
Add model to hold sorting data:
public class SortingParams
{
public string SortBy { get; set; } = "";
}
Add an extension method to IQueryable
:
public static IQueryable<T> Sort<T>(this IQueryable<T> source, string sortBy)
{
if (source == null)
throw new ArgumentNullException("source");
if (string.IsNullOrEmpty(sortBy))
throw new ArgumentNullException("sortBy");
source = source.OrderBy(sortBy);
return source;
}
Add output models (to send data via API):
public class MovieOutputModel
{
public List<MovieInfo> Items { get; set; }
}
public class MovieInfo
{
public int Id { get; set; }
public string Title { get; set; }
public int ReleaseYear { get; set; }
public string Summary { get; set; }
public string LeadActor { get; set; }
public DateTime LastReadAt { get; set; }
}
Add a service and domain model:
public interface IMovieService
{
List<Movie> GetMovies(FilteringParams filteringParams);
}
public class MovieService : IMovieService
{
public List<Movie> GetMovies(SortingParams sortingParams)
{
var query = this.movies.AsQueryable();
if (!string.IsNullOrEmpty(sortingParams.SortBy))
query = query.Sort(sortingParams.SortBy);
return query.ToList();
}
}
public class Movie
{
public int Id { get; set; }
public string Title { get; set; }
public int ReleaseYear { get; set; }
public string Summary { get; set; }
public string LeadActor { get; set; }
}
Add a controller for the API with service injected via constructor:
[Route("movies")]
public class MoviesController : Controller
{
private readonly IMovieService service;
public MoviesController(IMovieService service)
{
this.service = service;
}
[HttpGet(Name = "GetMovies")]
public IActionResult Get(SortingParams sortingParams)
{
var model = service.GetMovies(sortingParams);
var outputModel = new MovieOutputModel
{
Items = model.Select(m => ToMovieInfo(m)).ToList(),
};
return Ok(outputModel);
}
}
Output
Discussion
Let’s walk through the sample code step-by-step:
- Sorting information is usually received via query parameters. The POCO
SortingParams
simply hold this information and pass to service (or repository). - Service will then sort the data and returns a list.
Linq.Dynamic.Core
provides an extension method on IQueryable
that accepts sorting expression as a string
.
- We build our output model
MovieOutputModel
and return status code 200 (OK)
. The output model contains list of movies. As discussed in the previous post (CRUD), we map the domain model to an output model (MovieInfo
in this case).
Note: The sample is a very basic implementation of sorting. You will get a ParseException
if the field specified for sorting doesn’t exist on the model. Typically, you would either verify field’s existence or catch the exception.