Problem
How to implement filtering in ASP.NET Core Web API.
Solution
To an empty project update Startup
class to add services and middleware for MVC:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
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 filtering data:
1 2 3 4 |
public class FilteringParams { public string FilterBy { get; set; } = ""; } |
Add a service and domain model:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
public interface IMovieService { List<Movie> GetMovies(FilteringParams filteringParams); } public class MovieService : IMovieService { public List<Movie> GetMovies(FilteringParams filteringParams) { var query = this.movies.AsQueryable(); var filterBy = filteringParams.FilterBy.Trim().ToLowerInvariant(); if (!string.IsNullOrEmpty(filterBy)) { query = query .Where(m => m.LeadActor.ToLowerInvariant().Contains(filterBy) || m.Title.ToLowerInvariant().Contains(filterBy) || m.Summary.ToLowerInvariant().Contains(filterBy)); } 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 output models (to send data via API):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class MovieOutputModel { public int Count { get; set; } 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 controller for the API with service injected via constructor:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
[Route("movies")] public class MoviesController : Controller { private readonly IMovieService service; public MoviesController(IMovieService service) { this.service = service; } [HttpGet(Name = "GetMovies")] public IActionResult Get(FilteringParams filteringParams) { var model = service.GetMovies(filteringParams); var outputModel = new MovieOutputModel { Count = model.Count, Items = model.Select(m => ToMovieInfo(m)).ToList(), }; return Ok(outputModel); } } |
Output:
Discussion
Let’s walk through the sample code step-by-step:
- Filtering information is usually received via query parameters. The POCO
FilteringParams
simply hold this information and passes to service (or repository). - Service will then filter the data and returns a list.
- We build our output model
MovieOutputModel
and return status code200(OK)
. The output model contains:- Total number of items returned by the server.
- List of movies. As discussed in previous post (CRUD) we map the domain model to an output model (
MovieInfo
in this case).