Learn how you manage routing in Blazor for .NET Core and VS Code 
Tags: blazor, dotnet, tutorial, webdev
Published: 2020-06-24 18:05:28

---
title: Learn how you manage routing in Blazor for .NET Core and VS Code 
published: true
description: This article covers routing in Blazor, route parameters as well as query parameters
tags: blazor, dotnet, tutorial, webdev
series: blazor
canonical_url: https://softchris.github.io/pages/dotnet-blazor-routing.html
---

Follow me on [Twitter](https://twitter.com/chris_noring), happy to take your suggestions on topics or improvements /Chris

Here's a link to previous works I've written on Blazor. Blazor is a framework that enables you to build full-stack apps in C#. You don't have to mix a backend language with a frontend language like JavaScript. Not having this context switch is a thing that's truly powerful.

## References

- [Install .NET Core, latest version](https://dotnet.microsoft.com/download) Ensure you have the latest version of .NET core installed so you have all the Blazor templates installed with it.
- [Get started with blazor](https://docs.microsoft.com/en-us/aspnet/core/blazor/get-started?view=aspnetcore-3.1&tabs=visual-studio-code&wt.mc_id=devto-blog-chnoring) This is good starter page for Blazor.
- [Blazor routing](https://docs.microsoft.com/en-us/aspnet/core/blazor/fundamentals/routing?view=aspnetcore-3.1&wt.mc_id=devto-blog-chnoring) This page shows all you need to know about routing
- [Community blog post on Query parameters](https://www.infologs.in/tutorials/18/blazor/122/reading-query-string-parameter-in-blazor-component/)
- [My first article on Blazor](https://dev.to/dotnet/blazor-the-future-of-net-web-apps-a-first-look-m8)
- [My second article on Blazor + JavaScript](https://dev.to/dotnet/blazor-learn-to-get-the-best-of-both-worlds-with-javascript-interop-58pp)

## Routing

Routing, what do we mean by the term? It simply means how we set up navigation and how we deal with the URL of the app. More specifically this usually means the following:

- **Setting up simple routes**, this involves defining a route like `/products` and determine what component should respond when this route is entered in a Browser.
- **Dealing with complex routes and route parameters**, a complex route usually looks a bit more advanced like so `/orders/{orderId}/items/{itemId}`. This route has something called route parameters. Route parameters are parts of the route that instructs the app to get a specific piece of data. With this example, the route parameters are `orderId` and `itemId`. What the parameters convey in this case is that they want a specific order and a specific order item on that order. An example of the mentioned route pattern can look like so `/orders/111/item/1`. Other examples of complex routes can be the following `blog/{slug}`. This is a common pattern when creating a blog. It is the same idea as the order example and also uses route parameters, in this case `slug`.
- **Query parameters**, query parameters aren't part of the route technically but is the end of URL. Given a URL `/products?page=1&pageSize=10` the query parameters is everything that happens after the `?`. Parameters are separated by `&` and are key-value pairs.
- **Navigation**, there are two types of navigation that is interesting to look at:
   - **Clicking a link**, usually there's a specific component helping you produce a link that the user is able to click on.
   - **Programmatic navigation**, this involves navigating with code. This is usually the case if you need to perform some asynchronous work before navigating.

## Routing in Blazor

Let's work through a scenario to learn how to handle the most common route aspects. Our scenario is that of master-detail. A product list page and product detail page. We'll gradually add more capabilities to it as we go along. 

### -1- Adding a product list page

This is a simple page that needs to show a list of products. For data, we will use a simple static data class. 

1. Create a new Blazor project by typing in the following command in the terminal:

   ```bash
   dotnet new blazorwasm -o blazor-routing
   cd blazor-routing
   ```

   Now you have a blazor project ready to go.

1. Create a file `Data.cs` in the root of the project and give it the following content:

   ```csharp
   using System.Collections.Generic;
  
   namespace Data {
     public class Product
     {
       public int Id { get; set; }
       public string Name { get; set; }
     }

     public static class Products
     {
       private static List<Data.Product> products = new List<Data.Product>(){
         new Data.Product(){ Id = 1, Name = "Test"  },
         new Data.Product(){ Id = 2, Name = "Test2"  },
         new Data.Product(){ Id = 3, Name = "Test3"  },
         new Data.Product(){ Id = 4, Name = "Test4"  }
       };

      public static List<Product> GetProducts()
      {
        return products;
      }
    }
   }
   ```

1. In the `Pages` directory create a file `Products.razor` and give it the following content:

   ```html
   @page "/products"
   @inject NavigationManager NavigationManager

   <h1>Products</h1>
  

   @foreach (var product in products)
   {
     <div>
       <NavLink href="@product.Url" target="_blank">@product.Name</NavLink>
     </div>
   }

   @code {
     List<Data.Product> products;

     protected override void OnInitialized()
     {
        this.products = Data.Products.GetProducts(pageParam, pageSizeParam);
    }
   }
   ```

   Note how the `@page` directive at the top is used to instruct that Blazor that this component should listen to the route `/products`. You've also set up the navigation between the product list and product detail page. Let's have a closer look at this part:

   ```html
   @foreach (var product in products)
   {
     <div>
       <NavLink href="@product.Url" target="_blank">@product.Name</NavLink>
     </div>
   }
   ```

   By using `NavLink` it will create a link the user can click on. Note how `href` is pointing to `product.Url`. You don't have that property yet so let's fix that. Open up `Data.cs` and add it like so:

   ```csharp
   public class Product
   {
     public int Id { get; set; }
     public string Name { get; set; }
     public string Url
     {
       get
       {
         return "products/" + this.Id;
       }
     }
   }
   ```

### -2- Creating a product detail page.

Next, you will create a product detail page.

1. Create the file `Product.razor` under `Pages` directory. Give the file the following content:

   ```html
   @page "/products/{Id:int}"
   @inject NavigationManager NavigationManager

   <h1>A specific product</h1>

   This is for Id @Id

   <div>
     Here is the product: @product.Name
   </div>

   <div>
     <NavLink href="products" target="_blank">Products</NavLink>
   </div>

   @code {
     [Parameter]
     public int Id { get; set; }
   }
   ```

   Above you set up a route `@page "/products/{Id:int}"`. This means you are handling routes like so `/products/1` but now `/products/abc`. Note how you are coercing the route parameter to be an integer `{Id:Int}`. There's also another section of interest where you get hold of the router parameter:

   ```csharp
   [Parameter]
   public int Id { get; set; }
   ``` 

   This is great if we in a later stage want to do a data lookup based on the route parameter value. Additionally, note how you add navigation back to the `/products` route using the built-in component `NavLink`:

   ```razor
   <NavLink href="products" target="_blank">Products</NavLink>
   ```

  The `href` is pointing to `products` which is your product list page. The `NavLink` is translated into an anchor tag during compilation.

1. Try out the application at this point by running the following command in the terminal:

   ```bash
   dotnet build && dotnet run
   ```

   Yor app should now run at `http://localhost:5000`. Let's navigate to `http://localhost:5000/products`. You should see the following:

   ![Product list view](https://dev-to-uploads.s3.amazonaws.com/i/p3l8vlq4zz6xnmd9x29v.png)

### -3- Detail component data lookup

 Next, you will implement looking up specific data on the detail component. To do so you need to ensure you have a specific method in `Data.cs` that lets you select a specific item by id. 

1. Open up `Data.cs` and add the following method to the `Products` class:

   ```csharp
   public static Product GetProduct(int id) 
   {
     return products.SingleOrDefault(p => p.Id == id);
   }
   ```

1. Open up `Product.razor` and update the code to look like the following:

   ```html
   @page "/products/{Id:int}"
   @inject NavigationManager NavigationManager

   <h1>A specific product</h1>

   This is for Id @Id

   <div>
   Here is the product: @product.Name
   </div>

   <div>
     <NavLink href="products" target="_blank">Products</NavLink>
   </div>

   <button class="btn btn-primary" @onclick="Navigate">
     Navigate to products
   </button>

   @code {
     [Parameter]
     public int Id { get; set; }

     Data.Product product = null;

     protected override void OnParametersSet()
     {
       this.product = Data.Products.GetProduct(this.Id);
     }

     private void Navigate() 
     {
       NavigationManager.NavigateTo("products");
     }
   }
   ```

   Now above the declaration of the lifecycle method `OnParametersSet()`. This is a point at which `Id` has got its value and you can safely write code that asks for a specific `Product` with this code:

   ```csharp
   this.product = Data.Products.GetProduct(this.Id);
   ```

   Note also how programmatic navigation was added. In the template there is this section:

   ```html
   <button class="btn btn-primary" @onclick="Navigate">
     Navigate to products
   </button>
   ```

   In the code section there is a method `Navigate()`, like so:

   ```csharp
   private void Navigate() 
   {
     NavigationManager.NavigateTo("products");
   }
   ``` 

   What did it get `NavigationManager` from? It's added at the of the component like so:

   ```razor
   @inject NavigationManager NavigationManager
   ```

   `NavigationManager` is built into Blazor and helps us navigate among other things.

### -4- Adding query parameters

This is great we have our master-detail working. However, it would be great if we learn to use query parameters. So why is that? Query parameters help filter the response. Let's look at a route like so `/products?page=1&page=10`. What does that mean? The query parameters `page` and `pageSize` signals that we want to limit the response. Imagine that `/products` possibly might return millions of records. We don't want that. So what we do is to think of our data in terms of pages. Having `page=1` and `pageSize=10` means we want the first 10 records whereas `page=2` would mean we want records 11-20. 

To start using query parameters we need to both install an assembly and write some code to parse the query parameters from the URL.

1. In the terminal run the following command:

   ```bash
   dotnet add package Microsoft.AspNetCore.WebUtilities
   ```

   This will install the `WebUtilities` package from NuGet. 

1. Open up `Products.razor` file. Give it the following content:

   ```html
   @page "/products"
   @inject NavigationManager NavigationManager
   @using System.Linq
 
   <h1>Products</h1>
   Page: @pageParam  PageSize: @pageSizeParam

   @foreach (var product in products)
   {
     <div>
       <NavLink href="@product.Url" target="_blank">@product.Name</NavLink>
     </div>
   }

   @code {
     List<Data.Product> products;
     int? pageParam = null;
     int? pageSizeParam = null; 

     protected override void OnInitialized()
     {
        var uri = NavigationManager.ToAbsoluteUri(NavigationManager.Uri);

        if (Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(uri.Query).TryGetValue("page", out var param))
        {
          this.pageParam = Int32.Parse(param);
        }
        if (Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(uri.Query).TryGetValue("pageSize", out var param2))
        {
          this.pageSizeParam = Int32.Parse(param2); 
        }
        this.products = Data.Products.GetProducts(pageParam, pageSizeParam);
     }
   }
   ```

   The big addition here was the method `OnInitialized()`. There are a few things going on so let's take it line by line. 
  
   - Get the URI, we will need the Uri so it's easier to parse out the query parameters.
   
      ```csharp
      var uri = NavigationManager.ToAbsoluteUri(NavigationManager.Uri);   
      ```
   
   -  Parse out the parameters. For this you use the `QueryHelper` class with `uri.Query` as input parameter. Then you call `TryGetValue()` with the query parameter as an argument. You do this twice, once for `page` and once for `pageSize`. 
    
      ```csharp
      if (Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(uri.Query).TryGetValue("page", out var param))
      {
          this.pageParam = Int32.Parse(param);
      }
      if (Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(uri.Query).TryGetValue("pageSize", out var param2))
      {
        this.pageSizeParam = Int32.Parse(param2); 
      }
      ```

    - Call `GetProducts()` with the query parameters to get a filtered response.

       ```csharp
       this.products = Data.Products.GetProducts(pageParam, pageSizeParam);
       ```

1. Open up `Data.cs` as you will need to update the `GetProducts()` method a little. Ensure the `GetProducts()` method now looks like so:

   ```csharp
   public static List<Product> GetProducts(int? page, int? pageSize) 
    {
      if (page.HasValue && pageSize.HasValue) {
        var filtered = products.Skip((page.Value-1) * pageSize.Value).Take(pageSize.Value);
        return filtered.ToList();
      }
      return products;
    }
   ```

1. Let's test out the solution. Type the following command in the terminal:

   ```bash
   dotnet build && dotnet run
   ```
1. Navigate to `http://localhost:5000/products?page=1&pageSize=2`. You should now see the 2 first rows displayed like so:

   ![Filtered product list](https://dev-to-uploads.s3.amazonaws.com/i/fiavvd50tjd9ip4t43x5.png)

1. Change page by changing the `page` to `2` so the URL should now look like so `http://localhost:5000/products?page=2&pageSize=2`. Your UI should now look like so:

   ![Filterd product list page 2](https://dev-to-uploads.s3.amazonaws.com/i/1vjallkapod6z2ku0400.png)

## Summary

We've covered quite a few things here related to routing. Basic routing looking like so `/products` but also more complicated routing like so `/products/{id: Int}`. Additionally, we even showed how to use query parameters to further filter the response. I hope it was helpful.