Blazor - Work With Cassandra API In Cosmos DB

In this article, we will see how to create a Cosmos DB account with Cassandra API. Later we will create a Blazor application and connect with Cassandra database using “CassandraCSharpDriver” NuGet package.

Apache Cassandra is a free and open-source, distributed, wide column store, NoSQL database management system. It provides high availability with no single point of failure.

Azure Cosmos DB with Cassandra API can be used as the data store for apps written for Apache Cassandra.
 
Blazor is an experimental .NET web framework using C#/Razor and HTML that runs in the browser with WebAssembly. Blazor provides the benefits of a client-side web UI framework using .NET. I have already written some articles about Blazor in C# Corner.
 
Please refer to the below articles to get a basic idea about Blazor framework.

We will create an Address Book application. We will see all CRUD operations in Blazor with Cassandra database.

Step 1 - Create Cosmos DB account with Cassandra API

Please login to the Azure portal and choose to Create New Resource, Databases and Azure Cosmos DB.
 
Create Cosmos DB account with Cassandra API 
 
Please choose your resource group (Create a new resource group if you do not have any resource group) and give a name to Cosmos DB account. Also, choose the geographic location for the Cosmos DB account. Make sure you have chosen Cassandra as API. Currently, there are 5 APIs available in Cosmos DB.
 
Create Cosmos DB account with Cassandra API
 
You can review the account details and after successful validation please click the “Create” button.
 
Create Cosmos DB account with Cassandra API
 
It will take some to finish the deployment. You can see the status.
 
Create Cosmos DB account with Cassandra API
After some time, Cosmos DB will be successfully deployed.
 
Create Cosmos DB account with Cassandra API
 
You can click “Go to resource” button and open the Cosmos DB account. Please click the “Connection String” tab and get the connection details about the Cassandra database. We will use these connection details in our Blazor application later.
 
Create Cosmos DB account with Cassandra API
 
We can go to the “Data Explorer” tab to create a new Keyspace now. The keyspace is like a database and tables are created under this Keyspace.
 
Create Cosmos DB account with Cassandra API
 
We can create a new Keyspace now.
Create Cosmos DB account with Cassandra API
After successful creation of Keyspace, we can create a Table now. For Table creation, we must use CQL (Cassandra Query Language) commands.
 
Create Cosmos DB account with Cassandra API
 
Most of the CQL commands are like SQL commands. 
  1. CREATE TABLE IF NOT EXISTS sarathlal.addressbook
  2. (id text PRIMARY KEY, firstname text, lastname text,
  3.  gender text, address text, zipcode text,
  4.  country text, state text, phone text)

Step 2 - Create Blazor application.

Please open Visual Studio 2017 (I am using a free community edition) and create a Blazor app. Choose an ASP.NET Core Web Application project template.

Create Blazor application 
 
We can choose Blazor (ASP.NET Core hosted) template.
 
Create Blazor application
 
Our solution will be ready in a moment. Please note that there are three projects created in our solution - “Client”, “Server”, and “Shared”.

The client project contains all the client-side libraries and Razor Views, while the server project contains the Web API Controller and other business logic. The shared project contains the commonly shared files, like models and interfaces.

Create Blazor application
 
By default, Blazor created many files in these three projects. We can remove all the unwanted files like “Counter.cshtml”, “FetchData.cshtml”, “SurveyPrompt.cshtml” from Client project and “SampleDataController.cs” file from Server project and delete “WeatherForecast.cs” file from shared project too.
 
We can add “CassandraCSharpDriver” NuGet package to Shared project and server project. Both projects need this package. This package is used for creating connectivity between Blazor app and Cassandra.
 
Create Blazor application
 
As I mentioned earlier, we will create an Address Book application. We can create AddressBook model class now. Please create a “Models” folder in the Shared project and create AddressBook class inside this folder.

Please copy below code and paste to a new class.

AddressBook.cs
  1. using Cassandra.Mapping.Attributes;  
  2.   
  3. namespace BlazorWithCassandraAddressBook.Shared.Models  
  4. {  
  5.     [Table("addressbook")]  
  6.     public class AddressBook  
  7.     {  
  8.         [Column("id")]  
  9.         public string Id  
  10.         {  
  11.             get;  
  12.             set;  
  13.         }  
  14.         [Column("firstname")]  
  15.         public string FirstName  
  16.         {  
  17.             get;  
  18.             set;  
  19.         }  
  20.         [Column("lastname")]  
  21.         public string LastName  
  22.         {  
  23.             get;  
  24.             set;  
  25.         }  
  26.         [Column("gender")]  
  27.         public string Gender  
  28.         {  
  29.             get;  
  30.             set;  
  31.         }  
  32.         [Column("address")]  
  33.         public string Address  
  34.         {  
  35.             get;  
  36.             set;  
  37.         }  
  38.         [Column("zipcode")]  
  39.         public string ZipCode  
  40.         {  
  41.             get;  
  42.             set;  
  43.         }  
  44.         [Column("country")]  
  45.         public string Country  
  46.         {  
  47.             get;  
  48.             set;  
  49.         }  
  50.         [Column("state")]  
  51.         public string State  
  52.         {  
  53.             get;  
  54.             set;  
  55.         }  
  56.         [Column("phone")]  
  57.         public string Phone  
  58.         {  
  59.             get;  
  60.             set;  
  61.         }  
  62.     }  
  63. }  

Please note that we have used “Table” and “Column” properties in this class. This is derived from “Cassandra.Mapping.Attributes” and used to mention the Table name and Column names of Cassandra table.

We can create an “IDataAccessProvider” interface now. This interface will contain all the signature of DataAccess class and we will implement this interface in our DataAccess class later.

Please copy the below code and paste to the interface.
 
IDataAccessProvider.cs
  1. using System.Collections.Generic;  
  2. using System.Threading.Tasks;  
  3.   
  4. namespace BlazorWithCassandraAddressBook.Shared.Models  
  5. {  
  6.     public interface IDataAccessProvider  
  7.     {  
  8.         Task AddRecord(AddressBook addressBook);  
  9.         Task UpdateRecord(AddressBook addressBook);  
  10.         Task DeleteRecord(string id);  
  11.         Task<AddressBook> GetSingleRecord(string id);  
  12.         Task<IEnumerable<AddressBook>> GetAllRecords();  
  13.     }  
  14. }  

We can go to our Server project and create a new folder “DataAccess”. We will create a static class “CassandraInitializer” inside this folder. This class will be called from application Startup class and this will be used to initialize our Cassandra database.

CassandraInitializer.cs

  1. using Cassandra;  
  2. using System.Diagnostics;  
  3. using System.Net.Security;  
  4. using System.Security.Authentication;  
  5. using System.Security.Cryptography.X509Certificates;  
  6. using System.Threading.Tasks;  
  7.   
  8. namespace BlazorWithCassandraAddressBook.Server.DataAccess  
  9. {  
  10.     public static class CassandraInitializer  
  11.     {  
  12.         // Cassandra Cluster Configs        
  13.         private const string UserName = "Fill the details";  
  14.         private const string Password = "Fill the details";  
  15.         private const string CassandraContactPoint = "Fill the details";  
  16.         private static readonly int CassandraPort = 10350;  
  17.         public static ISession session;  
  18.   
  19.         public static async Task InitializeCassandraSession()  
  20.         {  
  21.             // Connect to cassandra cluster  (Cassandra API on Azure Cosmos DB supports only TLSv1.2)  
  22.             var options = new SSLOptions(SslProtocols.Tls12, true, ValidateServerCertificate);  
  23.             options.SetHostNameResolver((ipAddress) => CassandraContactPoint);  
  24.             Cluster cluster = Cluster.Builder().WithCredentials(UserName, Password).WithPort(CassandraPort).AddContactPoint(CassandraContactPoint).WithSSL(options).Build();  
  25.   
  26.             session = await cluster.ConnectAsync("sarathlal");  
  27.         }  
  28.   
  29.         public static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)  
  30.         {  
  31.             if (sslPolicyErrors == SslPolicyErrors.None)  
  32.                 return true;  
  33.   
  34.             Trace.WriteLine("Certificate error: {0}", sslPolicyErrors.ToString());  
  35.             // Do not allow this client to communicate with unauthenticated servers.  
  36.             return false;  
  37.         }  
  38.     }  
  39. }  

We have given the Cosmos DB Cassandra connection details inside the above class. A static Cassandra “Session” will be created at the application startup and will be shared across the entire application.

We can create the class “DataAccessCassandraProviderinside the DataAccess folder. This class will implement the interface IDataAccessProvider and define all the CRUD operations. We will call these methods from our Web API controller later.

Please copy the below code and paste to class.
 
DataAccessCassandraProvider.cs
  1. using BlazorWithCassandraAddressBook.Shared.Models;  
  2. using Cassandra;  
  3. using Cassandra.Mapping;  
  4. using Microsoft.Extensions.Logging;  
  5. using System;  
  6. using System.Collections.Generic;  
  7. using System.Linq;  
  8. using System.Threading.Tasks;  
  9.   
  10. namespace BlazorWithCassandraAddressBook.Server.DataAccess  
  11. {  
  12.     public class DataAccessCassandraProvider : IDataAccessProvider  
  13.     {  
  14.         private readonly ILogger _logger;  
  15.         private readonly IMapper mapper;  
  16.         public DataAccessCassandraProvider(ILoggerFactory loggerFactory)  
  17.         {  
  18.             _logger = loggerFactory.CreateLogger("DataAccessCassandraProvider");  
  19.             mapper = new Mapper(CassandraInitializer.session);  
  20.         }  
  21.   
  22.         public async Task AddRecord(AddressBook addressBook)  
  23.         {  
  24.             addressBook.Id = Guid.NewGuid().ToString();  
  25.             await mapper.InsertAsync(addressBook);  
  26.         }  
  27.   
  28.         public async Task UpdateRecord(AddressBook addressBook)  
  29.         {  
  30.             var updateStatement = new SimpleStatement("UPDATE addressbook SET " +  
  31.                 " firstname = ? " +  
  32.                 ",lastname  = ? " +  
  33.                 ",gender    = ? " +  
  34.                 ",address   = ? " +  
  35.                 ",zipcode   = ? " +  
  36.                 ",country   = ? " +  
  37.                 ",state     = ? " +  
  38.                 ",phone     = ? " +  
  39.                 " WHERE id  = ? ",  
  40.                 addressBook.FirstName, addressBook.LastName, addressBook.Gender,  
  41.                 addressBook.Address, addressBook.ZipCode, addressBook.Country,  
  42.                 addressBook.State, addressBook.Phone, addressBook.Id);  
  43.   
  44.             await CassandraInitializer.session.ExecuteAsync(updateStatement);  
  45.         }  
  46.   
  47.         public async Task DeleteRecord(string id)  
  48.         {  
  49.             var deleteStatement = new SimpleStatement("DELETE FROM addressbook WHERE id = ? ", id);  
  50.             await CassandraInitializer.session.ExecuteAsync(deleteStatement);  
  51.         }  
  52.   
  53.         public async Task<AddressBook> GetSingleRecord(string id)  
  54.         {  
  55.             AddressBook addressBook = await mapper.SingleOrDefaultAsync<AddressBook>("SELECT * FROM addressbook WHERE id = ?", id);  
  56.             return addressBook;  
  57.         }  
  58.   
  59.         public async Task<IEnumerable<AddressBook>> GetAllRecords()  
  60.         {  
  61.             IEnumerable<AddressBook> addressBooks = await mapper.FetchAsync<AddressBook>("SELECT * FROM addressbook");  
  62.             return addressBooks;  
  63.   
  64.         }  
  65.     }  
  66. }  

Please note we have defined all the CRUD operations inside above class. For that, we have used the Mapper object for inserting a Cassandra record and getting records from Cassandra. For update and delete we used Cassandra session Execute method.

We can initiate this DataAccess provider class inside the “Startup” class using dependency injection. We will also call the “InitializeCassandraSession” method inCassandraInitializer class from this Startup class.
 
Create Blazor application
 
Startup.cs
  1. using BlazorWithCassandraAddressBook.Server.DataAccess;  
  2. using BlazorWithCassandraAddressBook.Shared.Models;  
  3. using Microsoft.AspNetCore.Blazor.Server;  
  4. using Microsoft.AspNetCore.Builder;  
  5. using Microsoft.AspNetCore.Hosting;  
  6. using Microsoft.AspNetCore.ResponseCompression;  
  7. using Microsoft.Extensions.DependencyInjection;  
  8. using System.Linq;  
  9. using System.Net.Mime;  
  10. using System.Threading.Tasks;  
  11.   
  12. namespace BlazorWithCassandraAddressBook.Server  
  13. {  
  14.     public class Startup  
  15.     {  
  16.         public void ConfigureServices(IServiceCollection services)  
  17.         {  
  18.             services.AddMvc();  
  19.   
  20.             services.AddResponseCompression(options =>  
  21.             {  
  22.                 options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[]  
  23.                 {  
  24.                     MediaTypeNames.Application.Octet,  
  25.                     WasmMediaTypeNames.Application.Wasm,  
  26.                 });  
  27.             });  
  28.   
  29.             services.AddScoped<IDataAccessProvider, DataAccessCassandraProvider>();  
  30.   
  31.             Task t = CassandraInitializer.InitializeCassandraSession();  
  32.             t.Wait();  
  33.         }  
  34.   
  35.         public void Configure(IApplicationBuilder app, IHostingEnvironment env)  
  36.         {  
  37.             app.UseResponseCompression();  
  38.   
  39.             if (env.IsDevelopment())  
  40.             {  
  41.                 app.UseDeveloperExceptionPage();  
  42.             }  
  43.   
  44.             app.UseMvc(routes =>  
  45.             {  
  46.                 routes.MapRoute(name: "default", template: "{controller}/{action}/{id?}");  
  47.             });  
  48.   
  49.             app.UseBlazor<Client.Program>();  
  50.         }  
  51.     }  
  52. }  

We can create the Web API controller “AddressBooksController” now.

AddressBooksController.cs

  1. using BlazorWithCassandraAddressBook.Shared.Models;  
  2. using Microsoft.AspNetCore.Mvc;  
  3. using System.Collections.Generic;  
  4. using System.Threading.Tasks;  
  5.   
  6. namespace BlazorWithCassandraAddressBook.Server.Controllers  
  7. {  
  8.     public class AddressBooksController : Controller  
  9.     {  
  10.         private readonly IDataAccessProvider _dataAccessProvider;  
  11.   
  12.         public AddressBooksController(IDataAccessProvider dataAccessProvider)  
  13.         {  
  14.             _dataAccessProvider = dataAccessProvider;  
  15.         }  
  16.   
  17.         [HttpGet]  
  18.         [Route("api/AddressBooks/Get")]  
  19.         public async Task<IEnumerable<AddressBook>> Get()  
  20.         {  
  21.             return await _dataAccessProvider.GetAllRecords();  
  22.         }  
  23.   
  24.         [HttpPost]  
  25.         [Route("api/AddressBooks/Create")]  
  26.         public async Task Create([FromBody]AddressBook addressBook)  
  27.         {  
  28.             if (ModelState.IsValid)  
  29.             {  
  30.   
  31.                 await _dataAccessProvider.AddRecord(addressBook);  
  32.             }  
  33.         }  
  34.   
  35.         [HttpGet]  
  36.         [Route("api/AddressBooks/Details/{id}")]  
  37.         public async Task<AddressBook> Details(string id)  
  38.         {  
  39.             return await _dataAccessProvider.GetSingleRecord(id);  
  40.         }  
  41.   
  42.         [HttpPut]  
  43.         [Route("api/AddressBooks/Edit")]  
  44.         public async Task Edit([FromBody]AddressBook addressBook)  
  45.         {  
  46.             if (ModelState.IsValid)  
  47.             {  
  48.                 await _dataAccessProvider.UpdateRecord(addressBook);  
  49.             }  
  50.         }  
  51.   
  52.         [HttpDelete]  
  53.         [Route("api/AddressBooks/Delete/{id}")]  
  54.         public async Task Delete(string id)  
  55.         {  
  56.             await _dataAccessProvider.DeleteRecord(id);  
  57.         }  
  58.     }  
  59. }  

We have initializedIDataAccessProvider” interface in the controller constructor.

We have defined all the HTTP GET, PUT, DELETE, and POST methods for our CRUD actions inside this controller. Please note all these methods are asynchronous.

We have completed the coding part for Shared and Server projects. We can go to the Client project and modify existing “NavMenu.cshtml” file. This is a Razor view file and used for navigation purposes.

NavMenu.cshtml

  1. <div class="top-row pl-4 navbar navbar-dark">    
  2.     <a class="navbar-brand" href="">Address Book App</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.     
  11.         <li class="nav-item px-3">    
  12.             <NavLink class="nav-link" href="" Match=NavLinkMatch.All>    
  13.                 <span class="oi oi-home" aria-hidden="true"></span> Home    
  14.             </NavLink>    
  15.         </li>    
  16.     
  17.         <li class="nav-item px-3">    
  18.             <NavLink class="nav-link" href="/listaddressbooks">    
  19.                 <span class="oi oi-list-rich" aria-hidden="true"></span> Address Book Details    
  20.             </NavLink>    
  21.         </li>    
  22.     </ul>    
  23. </div>    
  24.     
  25. @functions {    
  26. bool collapseNavMenu = true;    
  27.     
  28. void ToggleNavMenu()    
  29. {    
  30.     collapseNavMenu = !collapseNavMenu;    
  31. }    
  32. }    
We can add “ListAddresBooks.cshtml” Razor view now. This view will be used to display all Address Book details.

ListAddresBooks.cshtml

  1. @using BlazorWithCassandraAddressBook.Shared.Models    
  2. @page "/listaddressbooks"    
  3. @inject HttpClient Http    
  4.     
  5. <h1>Address Book Details</h1>    
  6. <p>    
  7.     <a href="/addaddressbook">Create New Address Book</a>    
  8. </p>    
  9. @if (addressBooks == null)    
  10. {    
  11.     <p><em>Loading...</em></p>    
  12. }    
  13. else    
  14. {    
  15.     <table class='table'>    
  16.         <thead>    
  17.             <tr>    
  18.                 <th>First Name</th>    
  19.                 <th>Last Name</th>    
  20.                 <th>Gender</th>    
  21.                 <th>Address</th>    
  22.                 <th>ZipCode</th>    
  23.                 <th>Phone</th>    
  24.             </tr>    
  25.         </thead>    
  26.         <tbody>    
  27.             @foreach (var address in addressBooks)    
  28.             {    
  29.                 <tr>    
  30.                     <td>@address.FirstName</td>    
  31.                     <td>@address.LastName</td>    
  32.                     <td>@address.Gender</td>    
  33.                     <td>@address.Address</td>    
  34.                     <td>@address.ZipCode</td>    
  35.                     <td>@address.Phone</td>    
  36.                     <td>    
  37.                         <a href='/editaddressbook/@address.Id'>Edit</a>    
  38.                         <a href='/deleteaddressbook/@address.Id'>Delete</a>    
  39.                     </td>    
  40.                 </tr>    
  41.             }    
  42.         </tbody>    
  43.     </table>    
  44. }    
  45. @functions {    
  46. AddressBook[] addressBooks;    
  47.     
  48. protected override async Task OnInitAsync()    
  49. {    
  50.     addressBooks = await Http.GetJsonAsync<AddressBook[]>("/api/AddressBooks/Get");    
  51.    }      
  52. }    
Please add the below three Razor views also.
 
AddAddressBook.cshtml
  1. @using BlazorWithCassandraAddressBook.Shared.Models    
  2. @page "/addaddressbook"    
  3. @inject HttpClient Http    
  4. @inject Microsoft.AspNetCore.Blazor.Services.IUriHelper UriHelper    
  5.     
  6. <h2>Create Address Book</h2>    
  7. <hr />    
  8. <form>    
  9.     <div class="row">    
  10.         <div class="col-md-4">    
  11.             <div class="form-group">    
  12.                 <label for="FirstName" class="control-label">First Name</label>    
  13.                 <input for="FirstName" class="form-control" bind="@addressBook.FirstName" />    
  14.             </div>    
  15.             <div class="form-group">    
  16.                 <label for="Gender" class="control-label">Gender</label>    
  17.                 <select for="Gender" class="form-control" bind="@addressBook.Gender">    
  18.                     <option value="">-- Select Gender --</option>    
  19.                     <option value="Male">Male</option>    
  20.                     <option value="Female">Female</option>    
  21.                 </select>    
  22.             </div>    
  23.             <div class="form-group">    
  24.                 <label for="ZipCode" class="control-label">ZipCode</label>    
  25.                 <input for="ZipCode" class="form-control" bind="@addressBook.ZipCode" />    
  26.             </div>    
  27.             <div class="form-group">    
  28.                 <label for="State" class="control-label">State</label>    
  29.                 <input for="State" class="form-control" bind="@addressBook.State" />    
  30.             </div>    
  31.         </div>    
  32.         <div class="col-md-4">    
  33.             <div class="form-group">    
  34.                 <label for="LastName" class="control-label">Last Name</label>    
  35.                 <input for="LastName" class="form-control" bind="@addressBook.LastName" />    
  36.             </div>    
  37.             <div class="form-group">    
  38.                 <label for="Address" class="control-label">Address</label>    
  39.                 <input for="Address" class="form-control" bind="@addressBook.Address" />    
  40.             </div>    
  41.             <div class="form-group">    
  42.                 <label for="Country" class="control-label">Country</label>    
  43.                 <input for="Country" class="form-control" bind="@addressBook.Country" />    
  44.             </div>    
  45.             <div class="form-group">    
  46.                 <label for="Phone" class="control-label">Phone</label>    
  47.                 <input for="Phone" class="form-control" bind="@addressBook.Phone" />    
  48.             </div>    
  49.         </div>    
  50.     </div>    
  51.     <div class="row">    
  52.         <div class="col-md-4">    
  53.             <div class="form-group">    
  54.                 <input type="button" class="btn btn-default" onclick="@(async () => await CreateAddressBook())" value="Save" />    
  55.                 <input type="button" class="btn" onclick="@Cancel" value="Cancel" />    
  56.             </div>    
  57.         </div>    
  58.     </div>    
  59. </form>    
  60. @functions {    
  61.     
  62. AddressBook addressBook = new AddressBook();    
  63.     
  64. protected async Task CreateAddressBook()    
  65. {    
  66.     await Http.SendJsonAsync(HttpMethod.Post, "/api/AddressBooks/Create", addressBook);    
  67.     UriHelper.NavigateTo("/listaddressbooks");    
  68. }    
  69.     
  70. void Cancel()    
  71. {    
  72.     UriHelper.NavigateTo("/listaddressbooks");    
  73. }    
  74. }   

EditAddressBook.cshtml

  1. @using BlazorWithCassandraAddressBook.Shared.Models    
  2. @page "/editaddressbook/{Id}"    
  3. @inject HttpClient Http    
  4. @inject Microsoft.AspNetCore.Blazor.Services.IUriHelper UriHelper    
  5.     
  6. <h2>Edit</h2>    
  7. <h4>Address Book</h4>    
  8. <hr />    
  9.     
  10. <form>    
  11.     <div class="row">    
  12.         <div class="col-md-4">    
  13.             <div class="form-group">    
  14.                 <label for="FirstName" class="control-label">FirstName</label>    
  15.                 <input for="FirstName" class="form-control" bind="@addressBook.FirstName" />    
  16.             </div>    
  17.             <div class="form-group">    
  18.                 <label for="Gender" class="control-label">Gender</label>    
  19.                 <select for="Gender" class="form-control" bind="@addressBook.Gender">    
  20.                     <option value="">-- Select Gender --</option>    
  21.                     <option value="Male">Male</option>    
  22.                     <option value="Female">Female</option>    
  23.                 </select>    
  24.             </div>    
  25.             <div class="form-group">    
  26.                 <label for="ZipCode" class="control-label">ZipCode</label>    
  27.                 <input for="ZipCode" class="form-control" bind="@addressBook.ZipCode" />    
  28.             </div>    
  29.             <div class="form-group">    
  30.                 <label for="State" class="control-label">State</label>    
  31.                 <input for="State" class="form-control" bind="@addressBook.State" />    
  32.             </div>    
  33.         </div>    
  34.         <div class="col-md-4">    
  35.             <div class="form-group">    
  36.                 <label for="LastName" class="control-label">LastName</label>    
  37.                 <input for="LastName" class="form-control" bind="@addressBook.LastName" />    
  38.             </div>    
  39.             <div class="form-group">    
  40.                 <label for="Address" class="control-label">Address</label>    
  41.                 <input for="Address" class="form-control" bind="@addressBook.Address" />    
  42.             </div>    
  43.             <div class="form-group">    
  44.                 <label for="Country" class="control-label">Country</label>    
  45.                 <input for="Country" class="form-control" bind="@addressBook.Country" />    
  46.             </div>    
  47.             <div class="form-group">    
  48.                 <label for="Phone" class="control-label">Phone</label>    
  49.                 <input for="Phone" class="form-control" bind="@addressBook.Phone" />    
  50.             </div>    
  51.         </div>    
  52.     </div>    
  53.     <div class="row">    
  54.         <div class="form-group">    
  55.             <input type="button" class="btn btn-default" onclick="@(async () => await UpdateAddressBook())" value="Save" />    
  56.             <input type="button" class="btn" onclick="@Cancel" value="Cancel" />    
  57.         </div>    
  58.     </div>    
  59. </form>    
  60.     
  61. @functions {    
  62.     
  63. [Parameter]    
  64. string Id { get; set; }    
  65.     
  66. AddressBook addressBook = new AddressBook();    
  67.     
  68. protected override async Task OnInitAsync()    
  69. {    
  70.     addressBook = await Http.GetJsonAsync<AddressBook>("/api/AddressBooks/Details/" + Id);    
  71. }    
  72.     
  73. protected async Task UpdateAddressBook()    
  74. {    
  75.     await Http.SendJsonAsync(HttpMethod.Put, "api/AddressBooks/Edit", addressBook);    
  76.     UriHelper.NavigateTo("/listaddressbooks");    
  77.     
  78. }    
  79.     
  80. void Cancel()    
  81. {    
  82.     UriHelper.NavigateTo("/listaddressbooks");    
  83. }    
  84. }     

DeleteAddressBook.cshtml  

  1. @using BlazorWithCassandraAddressBook.Shared.Models    
  2. @page "/deleteaddressbook/{Id}"    
  3. @inject HttpClient Http    
  4. @inject Microsoft.AspNetCore.Blazor.Services.IUriHelper UriHelper    
  5.     
  6. <h2>Delete</h2>    
  7. <p>Are you sure you want to delete this Address with Id :<b> @Id</b></p>    
  8. <br />    
  9. <div class="col-md-4">    
  10.     <table class="table">    
  11.         <tr>    
  12.             <td>FirstName</td>    
  13.             <td>@addressBook.FirstName</td>    
  14.         </tr>    
  15.         <tr>    
  16.             <td>LastName</td>    
  17.             <td>@addressBook.LastName</td>    
  18.         </tr>    
  19.         <tr>    
  20.             <td>Gender</td>    
  21.             <td>@addressBook.Gender</td>    
  22.         </tr>    
  23.         <tr>    
  24.             <td>Country</td>    
  25.             <td>@addressBook.Country</td>    
  26.         </tr>    
  27.         <tr>    
  28.             <td>Phone</td>    
  29.             <td>@addressBook.Phone</td>    
  30.         </tr>    
  31.     </table>    
  32.     <div class="form-group">    
  33.         <input type="button" value="Delete" onclick="@(async () => await Delete())" class="btn btn-default" />    
  34.         <input type="button" value="Cancel" onclick="@Cancel" class="btn" />    
  35.     </div>    
  36. </div>    
  37. @functions {    
  38.     
  39. [Parameter]    
  40. string Id { get; set; }    
  41.     
  42. AddressBook addressBook = new AddressBook();    
  43.     
  44. protected override async Task OnInitAsync()    
  45. {    
  46.     addressBook = await Http.GetJsonAsync<AddressBook>    
  47. ("/api/AddressBooks/Details/" + Id);    
  48. }    
  49.     
  50. protected async Task Delete()    
  51. {    
  52.     await Http.DeleteAsync("api/AddressBooks/Delete/" + Id);    
  53.     UriHelper.NavigateTo("/listaddressbooks");    
  54. }    
  55.     
  56. void Cancel()    
  57. {    
  58.     UriHelper.NavigateTo("/listaddressbooks");    
  59. }    
  60. }     
We have completed all the coding part now. We can run the Address Book app now.

Create Blazor application
 
We can add a new Address Book record now.
 
Create Blazor application
 
We can add one more record and display the records.
 
 Create Blazor application
 
We can edit one record.
 
Create Blazor application
 

I have changed the address field.

Now we can delete one record.

Create Blazor application
 
We can check the data in Azure Cosmos DB account also. Please open Data Explorer tab and click CQL Query Text and Run. We will see one address book record created by our Blazor application.
 
Create Blazor application
 
In this article, we have seen how to create a Cosmos DB account with Cassandra API and we created a Blazor application with ASP.NET Core hosted template. We have used CassandraCSharpDriver NuGet package to connect Blazor with Cassandra. We used some CQL (Cassandra Query Language) commands inside our DataAccess provider class. We have seen all CRUD operations with our Address Book application.
 
We will see more Blazor features in upcoming articles.