Cascading DropDownList In Blazor Using EF Core

Introduction

In this article, we are going to create a cascading dropdown list in Blazor using Entity Framework Core database first approach. We will create two dropdown lists – Country and City. On selecting the value from country dropdown, we will change the value of City dropdown.

We will be using Visual Studio 2017 and SQL Server 2014.

Take a look at the final application.

 

Prerequisites

  • Install .NET Core 2.1 Preview 2 SDK from here
  • Install Visual Studio 2017 v15.7 or above from here
  • Install ASP.NET Core Blazor Language Services extension from here
  • SQL Server 2008 or above
Blazor Framework is not supported by versions below Visual Studio 2017 v15.7.

Source Code

Before proceeding, I would recommend you to get the source code from GitHub.

Creating Tables

We will be using two tables to store our data.

  1. Country
    Used to store the name of Country. It contains two fields – CountryId and CountryName.

  2. Cities
    This contains the list of cities for the Countries we insert in Country table. It contains three fields – CityId, CountryId and CityName. The CountryId column is a foreign key referring to CountryId in Country table.
Execute the following commands to create both tables.
  1. CREATE TABLE Country  
  2. (  
  3. CountryId VARCHAR(5) PRIMARY KEY,  
  4. CountryName VARCHAR(20) NOT NULL  
  5. )  
  6. GO  
  7.   
  8. CREATE TABLE Cities  
  9. (  
  10. CityId VARCHAR(5) PRIMARY KEY,  
  11. CountryId VARCHAR(5) FOREIGN KEY REFERENCES Country(CountryId),  
  12. CityName VARCHAR(20) NOT NULL  
  13. )  
  14. GO  
Now we will put some data in both the tables. Open Country table and execute the following insert statement.
  1. INSERT INTO Country VALUES ('C1''India')  
  2. INSERT INTO Country VALUES ('C2''China')  
  3. INSERT INTO Country VALUES ('C3''USA')  
Execute the following insert statements to insert the data into Cities table.
  1. INSERT INTO Cities VALUES ('P1','C1','New Delhi')  
  2. INSERT INTO Cities VALUES ('P2','C1','Mumbai')  
  3. INSERT INTO Cities VALUES ('P3','C1','Chennai')  
  4. INSERT INTO Cities VALUES ('P4','C1','Hyderabad')  
  5. INSERT INTO Cities VALUES ('P5','C1','Bengaluru')  
  6. INSERT INTO Cities VALUES ('P6','C2','Beijing')  
  7. INSERT INTO Cities VALUES ('P7','C2','Shanghai')  
  8. INSERT INTO Cities VALUES ('P8','C2','Hong Kong')  
  9. INSERT INTO Cities VALUES ('P9','C2','Macau')  
  10. INSERT INTO Cities VALUES ('P10','C3','New York')  
  11. INSERT INTO Cities VALUES ('P11','C3','Chicago')  
  12. INSERT INTO Cities VALUES ('P12','C3','Las Vegas')  

Create Blazor Web Application

Open Visual Studio and select File >> New >> Project.

After selecting the project, a "New Project" dialog will open. Select .NET Core inside Visual C# menu from the left panel. Then, select “ASP.NET Core Web Application” from available project types. Put the name of the project as BlazorDDL and press OK.

 
 
After clicking on OK, a new dialog will open asking you to select the project template. You can observe two drop-down menus at the top left of the template window. Select “.NET Core” and “ASP.NET Core 2.0” from these dropdowns. Then, select “Blazor (ASP .NET Core hosted)” template and press OK.
 
 
 
Now, our Blazor solution will be created. You can observe the folder structure in Solution Explorer as shown in the below image.
 
 

You can observe that we have three project files created inside this solution.

  1. BlazorDDL.Client – It has the client side code and contains the pages that will be rendered on the browser.
  2. BlazorDDL.Server – It has the server side codes such as DB related operations and web API.
  3. BlazorDDL.Shared – It contains the shared code that can be accessed by both client and server. It contains out Model classes.

Scaffolding the Model to the Application

We are using Entity Framework core database first approach to create our models. We will create our model class in BlazorDDL.Shared project so that it can be accessible to both client and server project.
 
Navigate to Tools >> NuGet Package Manager >> Package Manager Console. Select “BlazorDDL.Shared” from Default project drop-down. Refer to image below,

 

First, we will install the package for the database provider that we are targeting which is SQL Server in this case. Hence, run the following command,
  1. Install-Package Microsoft.EntityFrameworkCore.SqlServer
Since we are using Entity Framework Tools to create a model from the existing database, we will install the tools package as well. Hence, run the following command,
  1. Install-Package Microsoft.EntityFrameworkCore.Tools
After you have installed both the packages, we will scaffold our model from the database tables using the following command,
  1. Scaffold-DbContext "Your connection string here" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -Tables Country, Cities
Do not forget to put your own connection string (inside " "). After this command is executed successfully, you can observe a Models folder has been created and it contains three class files myTestDBContext.cs, Cities.cs and Country.cs. Hence, we have successfully scaffolded our Models using EF core database first approach.

At this point in time, the Models folder will have the following structure.

 

Creating Data Access Layer for the Application

Right-click on BlazorDDL.Server project and then select Add >> New Folder and name the folder as DataAccess. We will be adding our class to handle database related operations inside this folder only.

Right click on DataAccess folder and select Add >> Class. Name your class DataAccessLayer.cs. This class will handle our database related operations.

Open DataAccessLayer.cs and put the following code into it.

  1. using BlazorDDL.Shared.Models;  
  2. using System;  
  3. using System.Collections.Generic;  
  4. using System.Linq;  
  5. using System.Threading.Tasks;  
  6.   
  7. namespace BlazorDDL.Server.DataAcces  
  8. {  
  9.     public class DataAccessLayer  
  10.     {  
  11.         myTestDBContext db = new myTestDBContext();  
  12.   
  13.         public IEnumerable<Country> GetAllCountries()  
  14.         {  
  15.             try  
  16.             {  
  17.                 return db.Country.ToList();  
  18.             }  
  19.             catch  
  20.             {  
  21.                 throw;  
  22.             }  
  23.         }  
  24.   
  25.         public IEnumerable<Cities> GetCityData(string id)  
  26.         {  
  27.             try  
  28.             {  
  29.                 List<Cities> lstCity = new List<Cities>();  
  30.                 lstCity = (from CityName in db.Cities where CityName.CountryId == id select CityName).ToList();  
  31.   
  32.                 return lstCity;  
  33.             }  
  34.             catch  
  35.             {  
  36.                 throw;  
  37.             }  
  38.         }  
  39.     }  
  40. }  

Here we have defined two methods

  1. GetAllCountries – It will fetch all the country data from the country table.
  2. GetCityData – It will fetch the city data corresponding to the country id provided to it.
Hence, our data access layer is complete. Now, we will proceed to create our web API Controller.

Adding the web API Controller to the Application

Right click on BlazorDDL.Server/Controllers folder and select Add >> New Item. An “Add New Item” dialog box will open. Select ASP.NET from the left panel, then select “API Controller Class” from templates panel and put the name as CountriesController.cs. Click Add.
 
 

This will create our API CountriesController class. We will call the methods of DataAccessLayer class to fetch data and pass on the data to the client side.

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Threading.Tasks;  
  5. using BlazorDDL.Server.DataAcces;  
  6. using BlazorDDL.Shared.Models;  
  7. using Microsoft.AspNetCore.Mvc;  
  8. using Microsoft.AspNetCore.Http;  
  9.   
  10. namespace BlazorDDL.Server.Controllers  
  11. {  
  12.     public class CountriesController : Controller  
  13.     {  
  14.         DataAccessLayer objCountry= new DataAccessLayer();  
  15.   
  16.         [HttpGet]  
  17.         [Route("api/Countries/GetCountryList")]  
  18.         public IEnumerable<Country> GetCountryList()  
  19.         {  
  20.             return objCountry.GetAllCountries();  
  21.         }  
  22.   
  23.         [HttpGet]  
  24.         [Route("api/Countries/GetCities/{id}")]  
  25.         public IEnumerable<Cities> GetCities(string id)  
  26.         {  
  27.             return objCountry.GetCityData(id);  
  28.         }  
  29.     }  
  30. }  

At this point of time, our BlazorDDL.Server project has the following structure.

 
 
We are done with our backend logic. Therefore, we will now proceed to code our client side.

Adding Razor View to the Application

Right click on BlazorDDL.Client/Pages folder and then select Add >> New Item. An “Add New Item” dialog box will open, select Web from the left panel, then select “Razor View” from templates panel and name it CountryData.cshtml. Click Add.
 
 

This will add a CountryData.cshtmlpage to our BlazorDDL.Client/Pages folder.

Open CountryData.cshtml page and put the following code into it.
  1. @using BlazorDDL.Shared.Models  
  2. @page "/country"  
  3. @inject HttpClient Http  
  4.   
  5. <h1>Country Data</h1>  
  6.   
  7. <p>This component demonstrates cascading dropdownlist using EntityFrameWork Core</p>  
  8. <hr />  
  9.   
  10. @if (countryList == null)  
  11. {  
  12.     <p><em>Loading...</em></p>  
  13. }  
  14. else  
  15. {  
  16.     <div class="row">  
  17.         <div class="col-md-4">  
  18.             <label for="Country" class="control-label">Country</label>  
  19.         </div>  
  20.         <div class="col-md-4">  
  21.             <label asp-for="Cities" class="control-label">Cities</label>  
  22.         </div>  
  23.     </div>  
  24.     <div class="row" style="padding-top:10px">  
  25.         <div class="col-md-4">  
  26.             <select class="form-control" onchange="@CountryClicked">  
  27.                 <option value="">-- Select Country --</option>  
  28.                 @foreach (var country in countryList)  
  29.                 {  
  30.                     <option value="@country.CountryId">@country.CountryName</option>  
  31.                 }  
  32.             </select>  
  33.         </div>  
  34.         <div class="col-md-4">  
  35.             <select class="form-control" onchange="@CityClicked">  
  36.                 <option value="">-- Select City --</option>  
  37.                 @if (cityList != null)  
  38.                 {  
  39.                     @foreach (var city in cityList)  
  40.                     {  
  41.                         <option value="@city.CityName">@city.CityName</option>  
  42.                     }  
  43.                 }  
  44.             </select>  
  45.         </div>  
  46.     </div>  
  47.     <div class="row" style="padding-top:50px">  
  48.         <div class="col-md-4">  
  49.             <label class="control-label">Country Name: @countryName</label>  
  50.         </div>  
  51.         <div class="col-md-4">  
  52.             <label class="control-label">City Name: @cityName</label>  
  53.         </div>  
  54.     </div>  
  55.   
  56. }  
  57.   
  58. @functions {  
  59.   
  60. List<Country> countryList = new List<Country>();  
  61. List<Cities> cityList = new List<Cities>();  
  62.   
  63. string countryId { get; set; }  
  64. string countryName { get; set; }  
  65. string cityName { get; set; }  
  66.   
  67. protected override async Task OnInitAsync()  
  68. {  
  69.     countryList = await Http.GetJsonAsync<List<Country>>("api/Countries/GetCountryList");  
  70. }  
  71.   
  72. protected async void CountryClicked(UIChangeEventArgs countryEvent)  
  73. {  
  74.     cityList.Clear();  
  75.     cityName = string.Empty;  
  76.   
  77.     countryId = countryEvent.Value.ToString();  
  78.     countryName = countryList.FirstOrDefault(s => s.CountryId == countryId).CountryName;  
  79.   
  80.     cityList = await Http.GetJsonAsync<List<Cities>>("api/Countries/GetCities/" + countryId);  
  81.     this.StateHasChanged();  
  82. }  
  83.   
  84. void CityClicked(UIChangeEventArgs cityEvent)  
  85. {  
  86.     cityName = cityEvent.Value.ToString();  
  87.     this.StateHasChanged();  
  88. }  
  89.   
  90. }  

Let’s understand this code.

On the top, we have included BlazorDDL.Shared.Models namespace so that we can use our Country and Cities model class in this page. We are defining the route of this page using @page directive. So, in this application, if we append “/country” to base URL then we will be redirected to this page. We are also injecting HttpClient service to enable web API call. 

Then we have defined the HTML section to display two Dropdown lists on our web page. We are calling the “CountryClicked” method on the onchange event of Country dropdown. This method will call GetCites web API method to fetch the city data from Cities table corresponding to the countryid of the selected country. We are also setting the value of countryName property to the selected country. The “StateHasChanged” method is invoked to refresh the UI. This will ensure that the City dropdown list will get refreshed on changing the country dropdown.

Similarly, we have another dropdown list to display city data corresponding to each country. On the onchange event of Cities dropdown, we are setting the value of cityName property to the selected city.

We are also displaying the selected country name and city name value on the webpage.

The @functions section has all our properties and methods. We have defined two variables – countryList of type Country and cityList of type City to handle the countries and cities data respectively. We have also declared three properties to handle countryId, countryName, and cityName data.

Inside the OnInitAsync method, we are calling the GetCountryList web API method to populate countryList. This variable is used to bind the data to Country dropdown list on page load.

Adding Link to Navigation menu

The last step is to add the link to our “CountryData” page in the navigation menu, open BlazorDDL.Client/Shared/NavMenu.cshtml page and put the following code into it.
  1. <div class="top-row pl-4 navbar navbar-dark">  
  2.     <a class="navbar-brand" href="/">BlazorDDL</a>  
  3.     <button class="navbar-toggler" onclick=@ToggleNavMenu>  
  4.         <span class="navbar-toggler-icon"></span>  
  5.     </button>  
  6. </div>  
  7.   
  8. <div class=@(collapseNavMenu ? "collapse" : null) onclick=@ToggleNavMenu>  
  9.     <ul class="nav flex-column">  
  10.         <li class="nav-item px-3">  
  11.             <NavLink class="nav-link" href="/" Match=NavLinkMatch.All>  
  12.                 <span class="oi oi-home" aria-hidden="true"></span> Home  
  13.             </NavLink>  
  14.         </li>  
  15.         <li class="nav-item px-3">  
  16.             <NavLink class="nav-link" href="/counter">  
  17.                 <span class="oi oi-plus" aria-hidden="true"></span> Counter  
  18.             </NavLink>  
  19.         </li>  
  20.         <li class="nav-item px-3">  
  21.             <NavLink class="nav-link" href="/fetchdata">  
  22.                 <span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data  
  23.             </NavLink>  
  24.         </li>  
  25.         <li class="nav-item px-3">  
  26.             <NavLink class="nav-link" href="/country">  
  27.                 <span class="oi oi-list-rich" aria-hidden="true"></span> Country  
  28.             </NavLink>  
  29.         </li>  
  30.     </ul>  
  31. </div>  
  32.   
  33. @functions {  
  34. bool collapseNavMenu = true;  
  35.   
  36. void ToggleNavMenu()  
  37. {  
  38.     collapseNavMenu = !collapseNavMenu;  
  39. }  
  40. }  

Hence, we have completed our cascading dropdown list application.

Execution Demo

Launch the application.

A web page will open as shown in the image below. The navigation menu on the left is showing navigation link for CountryData page.
 
 
 
Click on Country in the navigation menu. It will redirect to CountryData view where you can see two dropdown lists – Country and Cities on the page. Notice the URL has “/country ” appended to it as we have defined it using @page directive.
 
 
 
Here you can see both the dropdown lists. The Country dropdown list is already populated with the country data. If we select any country name from this drop-down, then the city dropdown will also get populated with the corresponding city data. We can also see the selected country and city values in the labels below both drop-down lists.
 
 
 
Deploying the application

To learn how to deploy a Blazor application using IIS , refer to Deploying a Blazor Application on IIS.

Conclusion

We have learned how to create cascading dropdown lists in Blazor using the Entity Framework Core database first approach with the help of Visual Studio 2017 and SQL Server 2014.

Please get the source code from Github and play around to get a better understanding.

See Also


Similar Articles