.NET Core (3.1)— CRUD Using Blazor And Entity Framework Core with PostGre Sql(Database)
By: Nitin Sharma
Tags: Postgresql, Blazor, Net Core 3, Postgres, Asp Net Mvc

In this article, I will be going through Performing CRUD operations on Blazor app by using entity framework core along with POSTGre Sql as backend.

What are We going To Learn ?

In this article we are going to learn how to perform crud operations using Blazor app in .net core along with using postgre sql for database. I will walk you though this process with code examples which make this more easy and understandable. Below are the steps we will be covering in this article:

Setup Blazor environment Setup postgre sql on localhost Integrate postgre sql with entity framework core create a demo blazor app

Introduction to Blazor

Blazor is an open source web framework which uses C# to develop web apps that runs on browser. It simplify the process of creating SPA which is single page application.

Why Blazor?

Blazor makes the web development easy and more productive because it uses the full stack development features of .Net. Moreover, Blazor is open source with great support from the community and it is fast as well.

It also uses the single page application feature such as :

Routing

Dependency Injection

Server Side rendering

Routing

Forms and Validation

Layouts

Prerequisites

Install .Net Core 3.1 SDK from here

Install Visual Studio 2019 from here

Download and Install PostGre Sql from here

Download and Install pgAdmin from here

Blazor Web Application

Lets jump into creation of our blazor application. To do this first we need to open visual studio and go to file -> New -> Project -> Blazor App

After selecting the option of blazor app we need to give any name to our blazor app and then we need to choose the Blazor webAssembly App option from the list of the available templates for Blazor app along with selecting the option of asp.net core hosted as below:

Note: If you are unable to see this option in your visual studio then you can run the following command in the .net cli and you will be able to see the Blazor webassembly app option in your visual studio.

Now after clicking on create we will be able to see the following project structure in our visual studio solution explorer:

You can observe that we have three project files in our solution explorer which are:

BlazorCRUDApp.client : This contains all the client side code and pages which will be rendered on the browser.

: This contains all the client side code and pages which will be rendered on the browser. BlazorCRUDApp.Server: This contains files related to database and webapis which simply means files related to server.

This contains files related to database and webapis which simply means files related to server. BlazorCRUDApp.Shared: This contains the code which will be shared between both the client and server

So if we run the app now in visual studio we will be able to see the below screen:

Here you can see we have a home page along with all the navigation on the left side where we can jump into the different pages for the app which is by default created in the blazor app. Lets replace this code with our real time app where we will create, update, delete and fetch the recipes.

Demo App

To start with our demo, firstly we need to create the Model with name of Recipe.cs in our shared project which will have some of the properties related to recipe whose implementation is as below:

Create data access layer in the Server project

Our next step is to create a class in our server project file which will be communicating to database; to do this we need to create a folder first with name ‘Data’ that can be create by right click on BlazorCRUDApp -> Add -> New Folder -> Data.

After Creating folder we need to add a class inside that folder which can be done by right clicking on folder and the Add-> Class -> RecipeContext.cs

New Folder inside BlazorCRUDApp.Server

Creating Class inside newly created folder

Integration of Entity Framework in RecipeContext.cs

Now we have to derive our RecipeContext.cs class with entity framework’s DbContext class but as we are going to work with post gre sql so we need to install the entity framework core package supported for postgre sql from package manager screen.

After installation of this package our RecipeContext.cs will looks like below:

In which we have to override one method to set up our connection string along with one virtual property whose name should be same with the name of the table in the database and this will help us to communicated with database to make any changes to our table in the database. Also, make sure you put your postgre sql connection string.

Data Access Layer

In next step we will be creating one more class in the same folder which will named as RecipeDbOperations.cs and this will handle all the CRUD related DB operations in our application. To achieve this we need to put the following code in RecipeDbOperations.cs.

using BlazorCRUDApp.Shared.Models;

using Microsoft.EntityFrameworkCore;

using System;

using System.Collections.Generic;

using System.Linq;

using System.Threading.Tasks; namespace BlazorCRUDApp.Server.Data { public class RecipeDbOperations{ RecipeContext rc = new RecipeContext(); //To Get all recipes public IEnumerable<Recipe> GetAllRecipes(){

try{

return rc.tblRecipe.ToList();

}

catch{throw;} } //To Add new recipe public void AddRecipe(Recipe recipe){ try{

rc.tblRecipe.Add(recipe);

rc.SaveChanges();

}

catch{throw;}

} //To Update particular recipe public void UpdateRecipe(Recipe recipe)

{

try{

rc.Entry(recipe).State = EntityState.Modified;

rc.SaveChanges();

} catch{throw;}

} //Get the particular recipe public Recipe GetEmployeeData(int id){ try{

Recipe recipe = rc.tblRecipe.Find(id);

Return recipe;

}

catch

{

throw;

}

} //To Delete particular recipe public void DeleteRecipe(int id)

{

try

{

Recipe recipe = rc.tblRecipe.Find(id);

rc.tblRecipe.Remove(recipe);

rc.SaveChanges();

} catch

{

throw;

}

}

}

}

Web Api Controller

Next step is to create web api which will use the functions of dboperation class to fetch and pass the data to client. The steps to create the webapi controller is as below:

We need to put below code in our newly create controller.

using System.Collections.Generic;

using BlazorCRUDApp.Server.Data;

using BlazorCRUDApp.Shared.Models;

using Microsoft.AspNetCore.Mvc; namespace BlazorCRUDApp.Server.Controllers

{

[Route("api/[controller]")]

public class RecipeController : Controller

{

private RecipeDbOperations dbOpereations = new RecipeDbOperations(); // GET: api/<controller>

[HttpGet]

public IEnumerable<Recipe> GetRecipes()

{

return dbOpereations.GetAllRecipes();

} // GET api/<controller>/5

[HttpGet("detail/{id}")]

public Recipe GetRecipeDetail(int id)

{

return dbOpereations.GetRecipeDetail(id);

} // POST api/<controller>

[HttpPost("create")]

public void Post([FromBody]Recipe recipe)

{

if (ModelState.IsValid)

dbOpereations.AddRecipe(recipe);

} // PUT api/<controller>/5

[HttpPut("edit")]

public void Put([FromBody]Recipe recipe)

{

if (ModelState.IsValid)

dbOpereations.UpdateRecipe(recipe);

} // DELETE api/<controller>/5

[HttpDelete("delete/{id}")]

public void Delete(int id)

{

dbOpereations.DeleteRecipe(id);

} } }

Now our project structure will looks like below:

Blazor Client Code (Razor Components)

After creating web api controller our next step is to create Razor Components. In our case we will be creating four razor components which should be fetchRecipe, addRecipe, editRecipe, deleteRecipe. Let’s take a look how to create our first razor component and the same process we need to follow to create next three components.

Steps to create a razor component

To create a razor component we need to go to blazor app’s client project file’s pages folder and on right clicking on it we need to go to the option add new item and from there we need to select razor component. See the screenshots for the process of creating razor component as below:

Now after creating all the razor components lets look at the code which needs to be added into these razor components.

FetchRecipe.razor

The fetch recipe page will be responsible to fetch all the detail of the recipe along with having action buttons such as edit and delete

@page "/fetchrecipe"

@using BlazorCRUDApp.Shared.Models

@inject HttpClient Http <h1>Recipe Detail</h1>

<p>

<a href="/addrecipe">Create New</a>

</p>

@if (recipes == null)

{

<p><em>Loading...</em></p>

}

else

{

<table class='table'>

<thead>

<tr>

<th>ID</th>

<th>Name</th>

<th>Ingredients</th>

<th>Description</th>

<th>Notes</th>

</tr>

</thead>

<tbody>

@foreach (var recipe in recipes)

{

<tr>

<td>@recipe.RecipeId</td>

<td>@recipe.Name</td>

<td>@recipe.Ingredients</td>

<td>@recipe.Description</td>

<td>@recipe.Notes</td>

<td>

<a href='/editrecipe/@recipe.RecipeId'>Edit</a> |

<a href='/delete/@recipe.RecipeId'>Delete</a>

</td>

</tr>

}

</tbody>

</table>

} @functions {

Recipe[] recipes;

protected override async Task OnInitializedAsync(){

recipes = await Http.GetJsonAsync<Recipe[]>("api/Recipe/recipes");

}

}

Let’s understand what does this code means, on the top we can see @page which is defining the url of the page which is ‘/fetchRecipe’ in our case. After that we are using shared namespace of our project so that we can use the Recipe class reference in our razor component. Furthermore, we have also referenced HttpClient class as well in our component whose main purpose is to make a webapi call.

The next part of the code contains html code which creates table for our recipe detail and also it contains two action links one is for edit and other is for deleting recipe which will be navigating to edit and delete recipe pages respectively whose url will be defined in their respective razor components.

The final part of our razor component contains the @functions section which contains all business logic for fetch recipe page. In that we have create a recipe array variable which will get populated inside OnInitializedAsync method by calling our fetch recipe webapi and it will bind to our html table on loading the page.

AddRecipe.razor

This razor component is responsible to create a new recipe for our application.

@using BlazorCRUDApp.Shared.Models

@page "/addrecipe"

@inject HttpClient Http

@inject Microsoft.AspNetCore.Components.NavigationManager Navigation <h1>Create Recipe</h1>

<hr /> <div class="row">

<div class="col-md-4">

<form>

<div class="form-group">

<label for="Name" class="control-label">Name</label>

<input for="Name" class="form-control" @bind="@recipe.Name" />

</div>

<div class="form-group">

<label asp-for="Ingredients" class="control-label">Ingredients</label> <textarea asp-for="Ingredients" class="form-control" @bind="@recipe.Ingredients" > </textarea>

</div> <div class="form-group">

<label asp-for="Notes" class="control-label">Notes</label

<textarea asp-for="Notes" class="form-control" @bind="@recipe.Notes" > </textarea>

</div> <div class="form-group">

<label asp-for="Description" class="control-label">Description</label>

<textarea asp-for="Description" class="form-control" @bind="@recipe.Description" ></textarea>

</div> <div class="form-group">

<button type="submit" class="btn btn-primary" @onclick="@(async () => await CreateRecipe())">Save</button>

<button class="btn btn-warning" @onclick="@cancel">Cancel</button>

</div>

</form>

</div>

</div> @functions {

Recipe recipe = new Recipe();

protected async Task CreateRecipe()

{

await Http.SendJsonAsync(HttpMethod.Post, "/api/Recipe/Create", recipe);

Navigation.NavigateTo("/fetchrecipe");

} void cancel()

{

Navigation.NavigateTo("/fetchrecipe");

}

}

To understand this component code lets start from the top of this as well.

Firstly, we are referring our shared project file again so that we can use the recipe class in our component, after that we have provided the route for this page as ‘/addRecipe’ along with adding reference to HttpClient class. Furthermore, we have also added reference to NavigationManager class to make url redirection possible.

Secondly, we have the html code which has all the fields to create a new recipe. If you have noticed we have used @bind inside the html components which binds the html component value with our Recipe class’s properties and vice versa. Moreover, our html code has two action links one is for creating a new recipe which is calling our business logics CreateRecipe function and second one is calling Cancel function.

Thirdly, we have implemented our business logic into two functions which are CreateRecipe and Cancel. CreateRecipe function takes our recipe class object and pass it to our webapi in the post request using object of HttpClient class so that the new recipe can be created in the database and the cancel function is used to redirect us to fetchRecipe page.

EditRecipe.razor

This component is used to update the detail of already created recipe.

@using BlazorCRUDApp.Shared.Models

@page "/editrecipe/{recipeId}"

@inject HttpClient Http

@inject Microsoft.AspNetCore.Components.NavigationManager Navigation <h2>Edit Recipe</h2>

<hr />

<div class="row">

<div class="col-md-4">

<form>

<div class="form-group">

<label for="Name" class="control-label">Name</label>

<input for="Name" class="form-control" @bind="@recipe.Name" />

</div>

<div class="form-group">

<label asp-for="Ingredients" class="control-label">Ingredients</label>

<textarea asp-for="Ingredients" class="form-control" @bind="@recipe.Ingredients"> </textarea>

</div> <div class="form-group">

<label asp-for="Description" class="control-label">Description</label>

<textarea asp-for="Description" class="form-control" @bind="@recipe.Description"> </textarea>

</div> <div class=" form-group">

<label asp-for="Notes" class="control-label">Notes</label

<textarea asp-for="Notes" class="form-control" @bind="@recipe.Notes" > </textarea>

</div> <div class="form-group">

<input type="submit" value="Save" @onclick="@(async () => await UpdateRecipe())" class="btn btn-primary" />

<input type="submit" value="Cancel" @onclick="@cancel" class="btn btn-warning" />

</div>

</form>

</div>

</div> @functions {

[Parameter]

public string recipeId { get; set; }

public Recipe recipe = new Recipe();

protected override async Task OnInitializedAsync()

{

recipe = await Http.GetJsonAsync<Recipe>("/api/Recipe/detail/" + Convert.ToInt32(recipeId));

} protected async Task UpdateRecipe()

{

await Http.SendJsonAsync(HttpMethod.Put, "api/Recipe/edit", recipe);

Navigation.NavigateTo("/fetchrecipe");

} void cancel()

{

Navigation.NavigateTo("/fetchrecipe");

}

}

In this component we have given this page with url editRecipe/{recipeId} where recipeId will be the parameter passed to this url from @functions section where we have added [Parameter] attribute on the recipeId which indicated that this is the parameter value of the url. Html part of this component is almost similar with our add recipe component which is also using @bind which is used to perform two way binding between html components and class object.

Inside our @functions section of edit recipe we have used recipeId inside onInitializedAsync function which is calling our get detail api to get the detail of the recipe whose id has been pass to the url and after getting the detail we are binding it with respective html components. Moreover, UpdateRecipe function updating our recipe detail which will be invoked by update action button and cancel method is redirecting us back to our fetchRecipe component which will be invoked by cancel action link.

DeleteRecipe.razor

This component is used to delete any create recipe from our database.

@using BlazorCRUDApp.Shared.Models

@page "/delete/{recipeId}"

@inject HttpClient Http

@inject Microsoft.AspNetCore.Components.NavigationManager Navigation <h2>Delete</h2>

<h3>Are you sure you want to delete recipe : @recipe.Name</h3>

<br /> <div class="col-md-4">

<table class="table">

<tr>

<td>Name</td>

<td>@recipe.Name</td>

</tr>

<tr>

<td>Ingredients</td>

<td>@recipe.Ingredients</td>

</tr>

<tr>

<td>Description</td>

<td>@recipe.Description</td>

</tr>

<tr>

<td>Notes</td>

<td>@recipe.Notes</td>

</tr>

</table>

<div class="form-group">

<input type="submit" value="Delete" @onclick="@(async () => await Delete())" class="btn btn-primary" />

<input type="submit" value="Cancel" @onclick="@cancel" class="btn btn-warning" />

</div>

</div> @functions {

[Parameter]

public string recipeId { get; set; }

Recipe recipe = new Recipe(); protected override async Task OnInitializedAsync()

{

recipe = await Http.GetJsonAsync<Recipe>

("/api/Recipe/detail/" + Convert.ToInt32(recipeId));

} protected async Task Delete()

{

await Http.DeleteAsync("api/Recipe/delete/" + Convert.ToInt32(recipeId));

Navigation.NavigateTo("/fetchrecipe");

} void cancel()

{

Navigation.NavigateTo("/fetchrecipe");

}

}

The route for the delete recipe is also parametrized because we are fetching the detail of the recipe which are going to delete.

Html part of this component is showing confirmation message followed by the detail of the recipe which we want to delete and inside @functions section we have the onInitialzedAsync method which will be fetch the detail of the recipe that we are going to delete along with two methods one is for delete which it self calls webapi of delete to delete the recipe, this action will be called by action link ‘delete’ and other method is cancel which is simply redirecting us to our fetchRecipe component and this action will be invoked by cancel action link.

NavMenu.razor

Last we need to update the navigation file to put our application link, for that we need to navigate to shared folder and then NavMenu.razor file. After navigating to the above mentioned path (BlazorCRUDApp.Client -> Shared -> NavMenu.razor) put the below code inside this file:

<div class="top-row pl-4 navbar navbar-dark">

<a class="navbar-brand" href="">BlazorCRUDApp</a>

<button class="navbar-toggler" @onclick="ToggleNavMenu">

<span class="navbar-toggler-icon"></span>

</button>

</div>

<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">

<ul class="nav flex-column">

<li class="nav-item px-3">

<NavLink class="nav-link" href="/" Match=NavLinkMatch.All>

<span class="oi oi-home" aria-hidden="true"></span> Home

</NavLink>

</li>

<li class="nav-item px-3">

<NavLink class="nav-link" href="/fetchRecipe">

<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch Recipe

</NavLink>

</li>

</ul>

</div> @code {

private bool collapseNavMenu = true;

private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;

private void ToggleNavMenu()

{

collapseNavMenu = !collapseNavMenu;

}

}

Working Demo

Launch the application and then you will be able to see the below screen on your browser.

Click on fetchRecipe link from left menu link which is followed by Home link. It will navigate to /fetchRecipe url

On clicking fetch recipe link it will redirects us to the recipe list page of our application which shows the saved recipes in our application. We will also see “Create New” link just below the Recipes which will redirects us add recipe component where we can create a new recipe. Lets click on the create new link and see what happens.

As we can see on clicking create new we navigated to create recipe component where we can add detail for our recipe we want to create and on clicking save the new recipe will be saved and we will be redirected to fetchRecipe component where we will be able to see the newly created recipe.

Now inside our fetch recipe component if we click on edit action of any recipe then lets see what happens.

On clicking on edit we can see we are now in our edit recipe component and here we can update any detail related to our recipe and after clicking on save the updated detail will be save and we will be redirected to fetchRecipe component. On other side, if we click on we will be redirected to fetchRecipe component.

On fetch recipe component if we click on delete button the we will be redirected to deleteRecipe component where we can delete our already created recipe by clicking on delete button and after deletion we will be redirected to fetchRecipe component where the deleted entry will disappear from the list of recipes.

Conclusion

In the conclusion of this article we have create a .net blazor app with all crud operations by using postgre sql as its backend for database. Firstly, we have set up our environment for the blazor app. Secondly, we have used entity framework core for postgre sql . Finally, we have created our application’s shared, server and client files and saw how to make them communicate with each other to make our application, a working demo.

Github Repo: Resources in GitHub

I hope this article will help you to understand how to work with blazor and create you own blazor app in case you are looking for resource i have provided in the link of git-hub, just clone that and run it and see the differences by your own. Happy Coding !

Thank you!!