In this post, we will discuss how to implement searching in ASP.NET Core web API applications. There are many components within the ASP.NET Core Web API that can make or break the API, and the complexity of implementing ASP.NET Core Web API’s search feature will vary depending on how you specify it.
If you simply want to search only one field in the database, you can easily implement that by implementing a basic search feature. Lucene.NET, for instance, is an already optimized and reliable search library that is good for dealing with multi-column multi-term searches.
When you get stuck, switching to the final branch will answer your question. Following along with the article is easy using the start branch.
NOTE: In order to follow this article, you must have some prior knowledge. The ASP.NET Core Web API series on Code Maze is heavily relied upon. It is strongly recommended that you review the underlying architecture and database set up if you don’t know how they work.
Let’s get started.
What is Searching?
Almost any web page on the world wide web has a search box.
If the website structure is familiar to us or if the website is not too large, finding something is easy. A search field will be more useful if we’re not sure what we’ll find, or if we’re trying to find the most relevant topic for us or if we’re visiting a large website for the first time.
It’s not difficult to implement the basic search for your website, but if you treat it lightly, the search function may be ineffective. When you need to search a website, using a Google dork or Google is often your best option. Google dorks are highly recommended if you are unfamiliar with them.
An owner’s name could be used as a search parameter in our simple project.
Let’s see how we can achieve that.
How to Implement Searching in ASP.NET Core Web API
The implementation of the most basic search in our project won’t be complicated at all since we’re going to implement the most basic search. Since we already covered paging and filtering, we have all the infrastructure we need. Our implementation will just be extended a bit.
As a result, we hope to accomplish the following:https://localhost:5001/api/owners?name=Anna Bosh
Only one result should be returned: Anna Bosh. Additionally, we need to remember that search needs to work with filtering and paging, so that’s another thing we should consider.
Because we’re sending our search query as a query parameter, we’re going to extend our OwnerParameters class first:
public class OwnerParameters : QueryStringParameters
{
public uint MinYearOfBirth { get; set; }
public uint MaxYearOfBirth { get; set; } = (uint)DateTime.Now.Year;
public bool ValidYearRange => MaxYearOfBirth > MinYearOfBirth;
public string Name { get; set; }
}
Name is the only new property we’ve added.
It’s as simple as that.
Name=”term” can now be used in queries.
Our OwnerRepository class needs to implement the search functionality next:
public PagedList<Owner> GetOwners(OwnerParameters ownerParameters)
{
var owners = FindByCondition(o => o.DateOfBirth.Year >= ownerParameters.MinYearOfBirth &&
o.DateOfBirth.Year <= ownerParameters.MaxYearOfBirth);
SearchByName(ref owners, ownerParameters.Name);
return PagedList<Owner>.ToPagedList(owners.OrderBy(on => on.Name),
ownerParameters.PageNumber,
ownerParameters.PageSize);
}
private void SearchByName(ref IQueryable<Owner> owners, string ownerName)
{
if (!owners.Any() || string.IsNullOrWhiteSpace(ownerName))
return;
owners = owners.Where(o => o.Name.ToLower().Contains(ownerName.Trim().ToLower()));
}
A simple IsNullOrWhiteSpace check on the Name property first determines whether or not we are actually receiving the name parameter. Looking for anything else is pointless if it’s not.
In the next step, we use the Where clause to match the Name strings trimmed (just in case). To search through fewer results, we do this after filtering.
As far as everything else is concerned, nothing changes.
The implementation is complete. We already had an infrastructure in place, so it wasn’t that difficult.
Implementing our plan and testing it
Our solution still needs to be tested.
In order to understand what our database table is like, let’s first recall how it looks.
Next, let’s search for Anna:https://localhost:5001/api/owners?name=Anna Bosh
Exactly as we expected, the results come in.
The result would be the same if we entered Anna Bosh’s full name. With .Contains(), a term is found by default as an entire string.
In this example, you can find all owners who start with o:
https://localhost:5001/api/owner?name=o
In order to get 3 results instead of 1 now, we need to do the following:
[
{
"id": "261e1685-cf26-494c-b17c-3546e65f5620",
"name": "Anna Bosh",
"dateOfBirth": "1974-11-14T00:00:00",
"address": "27 Colored Row"
},
{
"id": "24fd81f8-d58a-4bcc-9f35-dc6cd5641906",
"name": "John Keen",
"dateOfBirth": "1980-12-05T00:00:00",
"address": "61 Wellfield Road"
},
{
"id": "66774006-2371-4d5b-8518-2177bcf3f73e",
"name": "Nick Somion",
"dateOfBirth": "1998-12-15T00:00:00",
"address": "North sunny address 102"
}
]
Adding filtering and paging to that would be awesome:
https://localhost:5001/api/owner?name=o&minYearOfBirth=1974&maxYearOfBith=1985&pageSize=1&pageNumber=2
What is the correct result (hint: one result)? Feel free to leave us a comment if you guessed correctly.
This concludes our implementation and testing of the search functionality.
That’s it for now.
Final Thoughts:
Following is a summary of what we’ve covered in this article:
- Searching versus filtering: what is the difference?
- ASP.NET Core Web API searching implementation
- Here’s how to test our API’s search capabilities
- Paging and filtering are combined with search
Thank you for taking the time to read this short article. I’ll get back to you as soon as possible if you leave a comment with a question or suggestion.