Tuesday 14 November 2023

CRUD Operation in Blazor using ASP.NET Core

 --Blazor maitains persistant HTTP connection between the client(Browser) and the server using SignalR.

--On Button click the event sent to the server over SignalR connection. The server will hanlde the event & send back an updated HTML to the client.

--The Html sent maynot be the entire Html Page but a small part of it & hence the performance is faster.

--3 Hosting Models

---Blazor server

---Blazor assembly web App

---Blazor hybrid


--Create Blazor WebAssembly App

---Check checkbox ASP.Net Core Hosted

--In .Server Project

---Install from Nuget Package --EntityFramework

--In .Shared Project

---Add Models folder and class file



--We will start writing code snippet from .Server Project. 
I. Models>>DatabaseContext.cs and below are code snippets

using Microsoft.EntityFrameworkCore;
using UserInfo.Shared.Models;


namespace UserInfo.Server.Models
{
    public partial class DatabaseContext:DbContext
    {
        public DatabaseContext() { }
        public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options) { }
        public virtual DbSet<UsersInfo> Users { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<UsersInfo>(e =>
            {
                e.ToTable("UsersInfo");
                e.Property(e => e.UserId).HasColumnName("UserId");
                e.Property(e => e.UserName).HasMaxLength(50).IsUnicode(false);
                e.Property(e => e.Address).HasMaxLength(int.MaxValue).IsUnicode(false);
                e.Property(e => e.MobileNo);
                e.Property(e => e.EmailId).HasMaxLength(int.MaxValue).IsUnicode(false);
            });
            OnModelCreatingPartial(modelBuilder);
        }
        partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
    }
}

II. Interfaces>>IUserInfo.cs and below are code snippets

using UserInfo.Shared.Models;

namespace UserInfo.Server.Interfaces
{
    public interface IUserInfo
    {
        public List<UsersInfo> GetAllUsers();
        public UsersInfo GetUserInfo(int userId);
        public bool AddUser(UsersInfo usersInfo);
        public bool RemoveUser(int userId);
        public bool UpdateUser(UsersInfo usersInfo);

    }
}

III. Services>>UserInfoImpl.cs and below are code snippets

using UserInfo.Shared.Models;
using UserInfo.Server.Models;
using UserInfo.Server.Interfaces;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Server.IIS.Core;

namespace UserInfo.Server.Services
{
    public class UserInfoImpl:IUserInfo
    {
        readonly DatabaseContext context = new();
        public UserInfoImpl(DatabaseContext context) { 
        this.context = context;
        }  

        public bool AddUser(UsersInfo usersInfo)
        {
            try
            {
                context.Users.Add(usersInfo);
                var res = context.SaveChanges();
                if (res > 0)
                    return true;
            }
            catch { throw; }
            return false;
        }

        public bool UpdateUser(UsersInfo usersInfo)
        {
            try
            {
                context.Entry(usersInfo).State=EntityState.Modified;
                var res = context.SaveChanges();
                if (res > 0)
                    return true;
            }
            catch { throw; }
            return false;
        }

        public List<UsersInfo> GetAllUsers()
        {
            try
            {
                return context.Users.ToList();
            }
            catch { throw; }
        }

        public UsersInfo GetUserInfo(int userId)
        {
            try
            {
                UsersInfo? userInfo = context.Users.Find(userId);
                if (userInfo != null)
                {
                    return userInfo;
                }
                else
                    throw new ArgumentNullException();
            }
            catch { throw; }
        }

        public bool RemoveUser(int userId)
        {
            try
            {
                UsersInfo? userInfo = context.Users.Find(userId);
                if (userInfo != null)
                {
                    context.Users.Remove(userInfo);
                    var res = context.SaveChanges();
                    if (res > 0)
                        return true;
                }
            }
            catch { throw; }
            return false;
        }

    }
}

IV. Controllers>>UserController.cs and below are code snippets

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using UserInfo.Server.Interfaces;
using UserInfo.Shared.Models;

namespace UserInfo.Server.Controllers
{
    [Route("api/User")]
    [ApiController]
    public class UserController : ControllerBase
    {
        private readonly IUserInfo user;
        public UserController(IUserInfo user)
        {
            this.user = user;
        }

        [HttpGet]
        public async Task<List<UsersInfo>> Get()
        {
            return await Task.FromResult(user.GetAllUsers());   
        }

        [HttpGet("{id}")]
        public IActionResult Get(int id)
        {
            var res =user.GetUserInfo(id);
            if(res != null)
            {
                return Ok(res);
            }
            else
            {
                return NotFound();
            }
        }

        [HttpPost]
        public bool Post(UsersInfo userInfo)
        {
            var res = user.AddUser(userInfo);
            if (res)
                return true;
            return false;
        }

        [HttpPut]
        public bool Put(UsersInfo userInfo)
        {
            var res = user.UpdateUser(userInfo);
            if (res)
                return true;
            return false;
        }

        [HttpDelete("{id}")]
        public IActionResult Delete(int id)
        {
            var res = user.RemoveUser(id);
            if (res)
                return Ok(res);
            return NotFound();
        }

    }
}

V. AppSettings.json and below are code snippets

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "MyConn": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=BlazorAppDB;Integrated Security=True;Encrypt=False;TrustServerCertificate=False;"
  }
}

VI. Program.cs and below are code snippets

using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.EntityFrameworkCore;
using UserInfo.Server.Interfaces;
using UserInfo.Server.Models;
using UserInfo.Server.Services;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<DatabaseContext>(x => x.UseSqlServer(builder.Configuration.GetConnectionString("MyConn")));

// Add services to the container.
builder.Services.AddScoped<IUserInfo,UserInfoImpl>();

builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseWebAssemblyDebugging();
}
else
{
    app.UseExceptionHandler("/Error");
}

app.UseBlazorFrameworkFiles();
app.UseStaticFiles();

app.UseRouting();


app.MapRazorPages();
app.MapControllers();
app.MapFallbackToFile("index.html");

app.Run();

--Then we will start writing code snippet from .Shared Project. 
I. Models>>UsersInfo.cs and below are code snippets

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;

namespace UserInfo.Shared.Models
{
    public class UsersInfo
    {
        [Key] public int UserId { get; set; }
        [Required]public string UserName { get; set; }
        [Required] public string Address { get; set; }
        [Required] public long MobileNo { get; set; }
        [Required] public string EmailId { get; set; }
    }
}

--Then we will start writing code snippet from .Client Project. 

I. Pages>>FetchUserDetails.razor and below are code snippets
@page "/fetchuserdetails"
@using UserInfo.Shared.Models;
@inject HttpClient Http;//it will get the HTTP Request/Response from the provided URI.
@*API's URI*@
<h1>User Data</h1>
<p>Blazor Application CRUD Operation</p>
<div class="row">
    <div class="col-md-6">
        <a href="/user/add" class="btn btn-primary" role="button">
            <i class="fas fa-user-plus"></i>
            Add User
        </a>
    </div>
    <div class="input-group col">
        <input type="text" class="form-control" placeholder="Search User By Name" @bind="SearchString" @bind:event="oninput" @onkeyup="FilterUser" />
        @if (SearchString.Length > 0)
        {
            <div class="input-group-append">
                <button class="btn btn-danger" @onclick="ResetSearch">Reset</button>
            </div>
        }
    </div>
</div>
<br />
@if (userList == null)
{
    <p><em>Loading......</em></p>
}
else
{
    <table class="table table-striped align-middle table-bordered">
        <thead class="table-success">
            <tr>
                <th>UserId</th>
                <th>UserName</th>
                <th>Address</th>
                <th>Mobile No</th>
                <th>EmailId</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var u in userList)
            {
                <tr>
                    <td>@u.UserId</td>
                    <td>@u.UserName</td>
                    <td>@u.Address</td>
                    <td>@u.MobileNo</td>
                    <td>@u.EmailId</td>
                    <td>
                        <a href="/user/edit/@u.UserId" class="btn btn-success" role="button">Edit</a>
                        <a href="/user/delete/@u.UserId" class="btn btn-danger" role="button">Delete</a>
                    </td>
                </tr>
            }
        </tbody>
    </table>
}
@code {
    protected List<UsersInfo> userList = new();
    protected List<UsersInfo> searchUserData = new();
    UsersInfo user = new();
    protected string SearchString { get; set; } = String.Empty;

    protected override async Task OnInitializedAsync()
    {
        await GetUser();
    }

    protected async Task GetUser()
    {
        userList = await Http.GetFromJsonAsync<List<UsersInfo>>("api/User");
        searchUserData = userList;
    }

    protected void FilterUser()
    {
        if (!string.IsNullOrEmpty(SearchString))
        {
            userList = searchUserData.Where(x => x.UserName.IndexOf(SearchString,
                StringComparison.OrdinalIgnoreCase) != -1).ToList();
        }
        else
        {
            userList = searchUserData;
        }
    }

    protected void DeleteConfirm(int UserID)
    {
        user = userList.FirstOrDefault(x => x.UserId == UserID);
    }

    public void ResetSearch()
    {
        SearchString = String.Empty;
        userList = searchUserData;
    }
}

II. Pages>>AddUser.razor and below are code snippets

@page "/user/add"
@page "/user/edit/{userId:int}"
@using UserInfo.Shared.Models;
@inject HttpClient Http;
@inject NavigationManager nav;

@*Navigation in Angular*@
<h1>@Title New User</h1>
<hr/>
<h4 class="bg-success text-center text-white">@Result</h4>
<EditForm Model="@user" OnValidSubmit="SaveUser">
    <DataAnnotationsValidator/>
    <div class="mb-3">
        <label>Enter Name</label>
        <InputText class="form-control" @bind-Value="user.UserName" />
        <span><ValidationMessage For="@(()=>user.UserName)" /></span>
    </div>
    <div class="mb-3">
        <label>Enter Address</label>
        <InputTextArea class="form-control" @bind-Value="user.Address" />
        <span><ValidationMessage For="@(()=>user.Address)" /></span>
    </div>
    <div class="mb-3">
        <label>Enter Mobile No</label>
        <InputNumber class="form-control" @bind-Value="user.MobileNo" />
        <span><ValidationMessage For="@(()=>user.MobileNo)" /></span>
    </div>
    <div class="mb-3">
        <label>Enter EmailId</label>
        <InputText class="form-control" @bind-Value="user.EmailId" />
        <span><ValidationMessage For="@(()=>user.EmailId)" /></span>
    </div>

    <div class="form-group">
        <button type="submit" class="btn btn-primary">@BtnTxt</button>
        <button type="reset" class="btn btn-light" @onclick="Cancel">Cancel</button>
    </div>
</EditForm>

@code{
    [Parameter]
    public int userId{ get; set; }
    protected string Title = "Add";
    protected string BtnTxt = "Save";
    protected UsersInfo user = new();
    public string Result { get; set; } = string.Empty;
    protected override async Task OnParametersSetAsync()
    {
        if(userId!=0)
        {
            Title = "Edit";
            BtnTxt = "Update";
            user = await Http.GetFromJsonAsync<UsersInfo>("api/User/" + userId);
        }
    }

    protected async Task SaveUser()
    {
        if(user.UserId!=0)
        {
            await Http.PutAsJsonAsync("/api/User", user);
            Result = "User data updated successfully.";
        }
        else
        {
            await Http.PostAsJsonAsync("/api/User", user);
            Result = "New user added successfully.";
        }
    }

    protected void Cancel()
    {
        nav.NavigateTo("/fetchuserdetails");
    }
}

III. Pages>>DeleteUser.razor and below are code snippets

@page "/user/delete/{userId:int}"
@using UserInfo.Shared.Models;
@inject HttpClient Http;
@inject NavigationManager nav;
<h2>Delete User</h2>
<br/>
<div class="form-group">
    <h4 class="bg-danger text-white">Do you want to delete user?</h4>
    <table class="table">
        <tbody>
        <tr>
            <td>Name</td>
            <td>@user.UserName</td>
        </tr>
            <tr>
                <td>Address</td>
                <td>@user.Address</td>
            </tr>
            <tr>
                <td>MobileNo</td>
                <td>@user.MobileNo</td>
            </tr>
            <tr>
                <td>EmailId</td>
                <td>@user.EmailId</td>
            </tr>
        </tbody>
    </table>
    <div class="form-group">
        <input type="submit" value="Delete" class="btn btn-danger" @onclick="(async()=>await RemoveUser(user.UserId))"/>
        <input type="button" value="Cancel" class="btn btn-light" @onclick="(()=>Cancel())">Cancel</input>
    </div>

</div>

@code{
    [Parameter]
    public int userId{ get; set; }
    UsersInfo user = new();

    protected override async Task OnInitializedAsync()
    {
        user = await Http.GetFromJsonAsync<UsersInfo>("api/User/" + userId);
    }

    protected void Cancel()
    {
        nav.NavigateTo("/fetchuserdetails");
    }

    protected async Task RemoveUser(int userId)
    {
        await Http.DeleteAsync("api/User/" + userId);
        nav.NavigateTo("/fetchuserdetails");
    }
}

IV. Shared>>NavMenu.razor and below are code snippets

<div class="top-row ps-3 navbar navbar-dark">
    <div class="container-fluid">
        <a class="navbar-brand" href="">UserInfo</a>
        <button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu">
            <span class="navbar-toggler-icon"></span>
        </button>
    </div>
</div>

<div class="@NavMenuCssClass nav-scrollable" @onclick="ToggleNavMenu">
    <nav class="flex-column">
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="oi oi-home" aria-hidden="true"></span> Home
            </NavLink>
        </div>
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="counter">
                <span class="oi oi-plus" aria-hidden="true"></span> Counter
            </NavLink>
        </div>
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="fetchdata">
                <span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
            </NavLink>
        </div>
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="fetchuserdetails">
                <span class="oi oi-list-rich" aria-hidden="true"></span> Fetch User Details
            </NavLink>
        </div>
    </nav>
</div>

@code {
    private bool collapseNavMenu = true;

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

    private void ToggleNavMenu()
    {
        collapseNavMenu = !collapseNavMenu;
    }
}

V. App.razor and below are code snippets

<Router AppAssembly="@typeof(App).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1" />
    </Found>
    <NotFound>
        <PageTitle>Not found</PageTitle>
        <LayoutView Layout="@typeof(MainLayout)">
            <p role="alert">Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>

VI. Program.cs and below are code snippets

using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using UserInfo.Client;

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

await builder.Build().RunAsync();

--Table created in DB








No comments:

Post a Comment