Sorting in Blazor WebAssembly is implemented similarly as in any other application type. And by sorting, we mean ordering the data fetched from the backend by using some criterium. For example, the criterium is often a product name. It can also be something like the price, or we can combine both of those as a single criterium for ordering our products.

The sorting needs to be implemented both on the client-side (Blazor WebAssembly side) and the backend side – the Web API part.

To download the source code for this article, you can visit the Sorting in Blazor WebAssembly repository.

For the complete navigation for this series, you can visit the Blazor Series page.

We are going to divide this article into the following topics:

So, let’s get down to business.

Sorting Implementation in the Web API

To start things off, we are going to modify the ProductParameters class by adding a new property:

public class ProductParameters
{
    const int maxPageSize = 50; 
    public int PageNumber { get; set; } = 1; 
    private int _pageSize = 4; 
    public int PageSize 
    { 
        get 
        { 
            return _pageSize; 
        } 
        set 
        { 
            _pageSize = (value > maxPageSize) ? maxPageSize : value; 
        }
    }

    public string SearchTerm { get; set; }
    public string OrderBy { get; set; } = "name";
}

As you can see, we add only one property that will accept the query string parameter from the client-side and pass it to the server-side action. Additionally, we set the value for this property to the name as the default sorting value.

To continue, we are going to install the System.Linq.Dynamic.Core library, to help us with the server-side sorting logic:

PM>Install-Package System.Linq.Dynamic.Core -Version 1.1.0

We have to mention that we have an article about sorting and we won’t dive deep into explanations in this article. If you want to learn in more detail about this feature or why we use Dynamic Linq on the Web API side, feel free to read the article.

Now, let’s modify the RepositoryProductExtensions class by adding a sorting logic:

public static IQueryable<Product> Sort(this IQueryable<Product> products, string orderByQueryString) 
{ 
    if (string.IsNullOrWhiteSpace(orderByQueryString)) 
        return products.OrderBy(e => e.Name); 
            
    var orderParams = orderByQueryString.Trim().Split(','); 
    var propertyInfos = typeof(Product).GetProperties(BindingFlags.Public | BindingFlags.Instance); 
    var orderQueryBuilder = new StringBuilder(); 
            
    foreach (var param in orderParams) 
    { 
        if (string.IsNullOrWhiteSpace(param)) 
            continue; 
                
        var propertyFromQueryName = param.Split(" ")[0]; 
        var objectProperty = propertyInfos.FirstOrDefault(pi => pi.Name.Equals(propertyFromQueryName, StringComparison.InvariantCultureIgnoreCase)); 
                
        if (objectProperty == null) 
            continue; 
                
        var direction = param.EndsWith(" desc") ? "descending" : "ascending"; 
        orderQueryBuilder.Append($"{objectProperty.Name} {direction}, "); 
    } 
            
    var orderQuery = orderQueryBuilder.ToString().TrimEnd(',', ' '); 
    if (string.IsNullOrWhiteSpace(orderQuery)) 
        return products.OrderBy(e => e.Name); 
            
    return products.OrderBy(orderQuery); 
}

In this code, we dynamically create our orderQuery by using Reflection and the StringBuilder class and call the OrderBy method from the Linq.Dynamic.Core namespace, to execute that query.

For this logic to work, we have to include several namespaces:

using System.Linq;
using System.Reflection;
using System.Text;
using System.Linq.Dynamic.Core;

Finishing Touches and Testing Web API’s Sorting Implementation

All we have left to do is to call this method in the ProductRepository class:

public async Task<PagedList<Product>> GetProducts(ProductParameters productParameters)
{
    var products = await _context.Products
        .Search(productParameters.SearchTerm)
        .Sort(productParameters.OrderBy)
        .ToListAsync();

    return PagedList<Product>
        .ToPagedList(products, productParameters.PageNumber, productParameters.PageSize);
}

Excellent.

Let’s test this:

Testing Sort functionality with Postman

And we have our correct result. We can see only four products because the paging returns only 4 items per page, and we can see they are sorted by the price in descending order.

Now, let’s continue to the implementation of Sorting in BlazorWebAssembly.

Sorting in Blazor WebAssembly Application

The first thing we are going to do is to create new Sort.razor and .cs files in the Components folder:

Files for sorting in Blazor WebAssembly

Then, let’s add our select control in the razor file:

<section>
    <select class="form-control" @onchange="ApplySort">
        <option value="-1">- Sort By -</option>
        <option value="name">Name</option>
        <option value="price">Price</option>
        <option value="price desc">Price DESC</option>
    </select>
</section>

This is a simple drop-down list with a couple of options to use for the sorting purpose. We can notice the @onChange event that is going to trigger the ApplySort method as soon as we choose any of our options.

After this, we have to modify the class file as well:

public partial class Sort
{
    [Parameter]
    public EventCallback<string> OnSortChanged { get; set; }

    private async Task ApplySort(ChangeEventArgs eventArgs)
    {
        if (eventArgs.Value.ToString() == "-1")
            return;

        await OnSortChanged.InvokeAsync(eventArgs.Value.ToString());
    }
}

We have a single event callback parameter and the ApplySort method with the ChangeEventArgs parameter. As soon as we pick our sorting option, the ApplySort method will trigger and if the value is different from -1, we call the OnSortChanged event callback and execute the parent function with the sorting value.

That said, we have to modify the Products page as well.

Let’s start with the razor file:

<div class="row">
    <div class="col-md-5">
        <Search OnSearchChanged="SearchChanged"/>
    </div>
    <div class="col-md-5">
        <Sort OnSortChanged="SortChanged" />
    </div>
    <div class="col-md-2">
        <a href="/createProduct">Create Product</a>
    </div>
</div>
<div class="row">
    <div class="col">
        <ProductTable Products="ProductList" />
    </div>
</div>
<div class="row">
    <div class="col">
        <Pagination MetaData="MetaData" Spread="2" SelectedPage="SelectedPage" />
    </div>
</div>

And continue with the class file, by adding a new method:

private async Task SortChanged(string orderBy)
{
    Console.WriteLine(orderBy);
    _productParameters.OrderBy = orderBy;
    await GetProducts();
} 

This method is going to be invoked from the Sort component with the OnSortChanged event callback and will accept the orderBy parameter. Then, we just log that value (for testing purpose), set the OrderBy property of the _productParameters object, and call the GetProducts function to refresh the product list on the screen.

Applying a QueryString Parameter

Of course, we have to apply this orderBy value to our HTTP request as a query string. To do that, we are going to modify the GetProducts method in the ProductHttpRepository class:

public async Task<PagingResponse<Product>> GetProducts(ProductParameters productParameters)
{
    var queryStringParam = new Dictionary<string, string>
    {
        ["pageNumber"] = productParameters.PageNumber.ToString(),
        ["searchTerm"] = productParameters.SearchTerm == null ? "" : productParameters.SearchTerm,
        ["orderBy"] = productParameters.OrderBy
    };

    //the rest of the code
            
    return pagingResponse;
}

That’s all it takes.

Testing Our Application

Finally, we can start the server-side and the client-side applications, navigate to the Products page, and test all of the functionalities:

Test Sorting in Blazor WebAssembly

As we can see, everything is working without a problem.

Conclusion

Excellent.

We have learned how to implement Sorting in Blazor WebAssembly application.

So, we are ready to continue with the Blazor WebAssembly Forms and Validation. And that’s exactly what we are going to learn about in the next article.