Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=BlazorAppDB;Integrated Security=True;Encrypt=False;TrustServerCertificate=False;
There are 3 different Projects will be created Client, Server and Shared.
Areas>>Identity>>Pages>>Account folder
Controllers>>OidConfigurationController.cs
Data folder>>Migration folder
Models folder>>ApplicationUser.cs
III. In .Shared Project
--We will start writing code snippet from .Server Project.
First Add DBContext:
i. Data folder>>ApplicationDbContext.cs and below are the code snippet
using BlazorIdentityAuthApp.Server.Interfaces;
using BlazorIdentityAuthApp.Server.Models;
using BlazorIdentityAuthApp.Shared.Models;
using Duende.IdentityServer.EntityFramework.Options;
using Microsoft.AspNetCore.ApiAuthorization.IdentityServer;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
namespace BlazorIdentityAuthApp.Server.Data
{
public class ApplicationDbContext : ApiAuthorizationDbContext<ApplicationUser>
{
public ApplicationDbContext(
DbContextOptions options,
IOptions<OperationalStoreOptions> operationalStoreOptions) : base(options, operationalStoreOptions)
{
}
public virtual DbSet<UsersInfo> UsersInfo { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Configure the UsersInfo entity
modelBuilder.Entity<UsersInfo>(entity =>
{
entity.HasKey(e => e.UserId);
entity.Property(e => e.UserName).IsRequired();
entity.Property(e => e.Address).IsRequired();
entity.Property(e => e.MobileNo).IsRequired();
entity.Property(e => e.EmailId).IsRequired();
});
}
}
}
ii. Interfaces folder>>IUsersInfo.cs and below are the code snippet
using BlazorIdentityAuthApp.Shared.Models;
namespace BlazorIdentityAuthApp.Server.Interfaces
{
public interface IUsersInfo
{
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 folder>>UsersInfoImpl.cs and below are the code snippet
using BlazorIdentityAuthApp.Server.Data;
using BlazorIdentityAuthApp.Server.Interfaces;
using BlazorIdentityAuthApp.Shared.Models;
using Microsoft.EntityFrameworkCore;
namespace BlazorIdentityAuthApp.Server.Services
{
public class UsersInfoImpl:IUsersInfo
{
private readonly ApplicationDbContext context;
public UsersInfoImpl(ApplicationDbContext context)
{
this.context = context;
}
public bool AddUser(UsersInfo usersInfo)
{
try
{
context.UsersInfo.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.UsersInfo.ToList();
}
catch { throw; }
}
public UsersInfo GetUserInfo(int userId)
{
try
{
UsersInfo? userInfo = context.UsersInfo.Find(userId);
if (userInfo != null)
{
return userInfo;
}
else
throw new ArgumentNullException();
}
catch { throw; }
}
public bool RemoveUser(int userId)
{
try
{
UsersInfo? userInfo = context.UsersInfo.Find(userId);
if (userInfo != null)
{
context.UsersInfo.Remove(userInfo);
var res = context.SaveChanges();
if (res > 0)
return true;
}
}
catch { throw; }
return false;
}
}
}
iv. Controller folder>>UsersInfoController.cs and below are the code snippet
using BlazorIdentityAuthApp.Server.Interfaces;
using BlazorIdentityAuthApp.Shared.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace BlazorIdentityAuthApp.Server.Controllers
{
[Route("api/User")]
[ApiController]
//[Authorize(Roles ="Admin,User")]
public class UsersInfoController : ControllerBase
{
private readonly IUsersInfo user;
public UsersInfoController(IUsersInfo 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}")]
[Authorize(Roles = "Admin")]
public IActionResult Delete(int id)
{
var res = user.RemoveUser(id);
if (res)
return Ok(res);
return NotFound();
}
}
}
v. Program.cs file and below are the code snippet
using BlazorIdentityAuthApp.Server.Data;
using BlazorIdentityAuthApp.Server.Models;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using BlazorIdentityAuthApp.Server.Services;
using BlazorIdentityAuthApp.Server.Interfaces;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
//Added Roles
builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
// Add services to the container.
builder.Services.AddScoped<IUsersInfo, UsersInfoImpl>();
//Added Auth Cookie
builder.Services.AddAuthentication("Identity.Application").AddCookie();
builder.Services.AddAuthentication()
.AddIdentityServerJwt();
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
app.UseWebAssemblyDebugging();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseIdentityServer();
//Added Auth
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();
app.MapControllers();
app.MapFallbackToFile("index.html");
app.Run();
vi. appsettings.json file and below are the code snippet
{
"ConnectionStrings": {
"DefaultConnection": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=BlazorAppDB;Integrated Security=True;Encrypt=False;TrustServerCertificate=False;"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"IdentityServer": {
"Clients": {
"BlazorIdentityAuthApp.Client": {
"Profile": "IdentityServerSPA"
}
}
},
"AllowedHosts": "*"
}
--Then we will start writing code snippet from .Shared Project.
i. Models folder>>UsersInfo.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BlazorIdentityAuthApp.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 the code snippet
@page "/fetchuserdetails"
@using BlazorIdentityAuthApp.Shared.Models;
@using System.Net;
@using Microsoft.AspNetCore.Authorization;
@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 the code snippet
@page "/user/add"
@page "/user/edit/{userId:int}"
@using BlazorIdentityAuthApp.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 the code snippet
@page "/user/delete/{userId:int}"
@using BlazorIdentityAuthApp.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 the code snippet
<div class="top-row ps-3 navbar navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="">BlazorIdentityAuthApp</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">
<AuthorizeView>
<Authorized>
<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>
<div class="nav-item px-3">
<NavLink class="nav-link" href="/identity/account/logout">
<span class="oi oi-power-standby" aria-hidden="true"></span> Log Out
</NavLink>
</div>
</Authorized>
<NotAuthorized>
<div class="nav-item px-3">
<NavLink class="nav-link" href="/identity/account/login">
<span class="oi oi-lock-locked" aria-hidden="true"></span> Login
</NavLink>
</div>
</NotAuthorized>
</AuthorizeView>
</nav>
</div>
@code {
private bool collapseNavMenu = true;
private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;
private void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
}
v. App.razor and below are the code snippet
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
<NotAuthorized>
@if (context.User.Identity?.IsAuthenticated != true)
{
<RedirectToLogin />
}
else
{
<p role="alert">You are not authorized to access this resource.</p>
}
</NotAuthorized>
</AuthorizeRouteView>
<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>
</CascadingAuthenticationState>
vi. Program.cs and below are the code snippet
using BlazorIdentityAuthApp.Client;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");
builder.Services.AddHttpClient("BlazorIdentityAuthApp.ServerAPI", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
// Supply HttpClient instances that include access tokens when making requests to the server project
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("BlazorIdentityAuthApp.ServerAPI"));
builder.Services.AddApiAuthorization();
await builder.Build().RunAsync();
No comments:
Post a Comment