0% found this document useful (0 votes)
17 views158 pages

Dot Net Notes

The document provides an overview of ASP.NET and web application development, detailing the differences between .NET Framework and .NET Core, as well as the architecture and components involved in ASP.NET applications. It covers database handling, data types, SQL commands, and the MVC architecture with Entity Framework, including examples of CRUD operations. Additionally, it discusses configuration settings in Web.config and the use of ADO.NET for data access.

Uploaded by

testingmastee
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views158 pages

Dot Net Notes

The document provides an overview of ASP.NET and web application development, detailing the differences between .NET Framework and .NET Core, as well as the architecture and components involved in ASP.NET applications. It covers database handling, data types, SQL commands, and the MVC architecture with Entity Framework, including examples of CRUD operations. Additionally, it discusses configuration settings in Web.config and the use of ADO.NET for data access.

Uploaded by

testingmastee
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 158

ASP.

NET & WEB APPs Key Notes (Made by : Rishi, 8607516403)

Framework: It is a software and load on server.


i) .Net Framework (old)  run only on Microsoft server.
ii) .Net Core (New)  platform independent (run on any server).
Framework architecture: [ .Net]
CLR  this environment manages the execution of code.
It is also managing the—

 Memory,
 Garbage collection {it is used to destroy the memory forcefully, which is used mainly
in for Heap memory management.
Example-
ABC obj;
(This type of object define/store in Stack Memory),

ABC Obj = New Obj();


(This type of object define/store in Heap Memory).
 Also support the multiple language (90+ programming language).

CLS – set of standards, BCL—int16, int32, int64


ASP.NET (Active Server Pages) – It is a technology (group) that run on the server and use for web
development.
Compilation process: -

ASP.NET is just tech. that runs on the web server and use for web development.
Server— use for user managements.

Web server—it is use for manage and run the web application.

1. IIS (Web server)—Internet information Server, it work/ install only on Microsoft server.
2. KESTRAL—run on MS server and non-MS server.

HTTPS—S stands for Secure Socket Layer


Public (access outside from the application)
Class accessor –
Internal (access within project/ application)

Class member accessor – public, private, protected, internal, protected internal

 Class has two types of members –


(i) static -- access with class
(ii) non-static – access with class object
 non-static can be access in static.
 Method should be called into the project/ page/ application.
 Events auto call/ fired when run the page/ application/ project.
 All Events has only two parameters – first for reference and second for manage event data from or
to the server.
 Variable, Properties both are used for store and retrieve the data.
 Properties maybe read only, write only, used for validation check and only control by the
developer.
 ASP.NET has only three types of buttons – submit/push, link, image.
 Class has a default constructor, which is use for assign the default value of any variable when the
object of class is called.
 Hyperlink – use for simple navigation. It works without refresh/ submit the page.
 Button – the button uses as a link, when implement some logic and go to the next page.

Database – handling

 Database is of two types –


(i) File server database
(ii) Client server database

 File server database – use in single user application. Exa – MS excess.


 Client server database – use for multiuser application/ web application. Exa – Oracle, MySQL, MS
SQL Server.

Database Master user User

 Types of Int data type – TinyInt (max size 1bytes/ 0 – 255)

SmallInt (2 bytes (65000 value)

Int (4 bytes)

BigInt (8 bytes)

 Primary Key – use as a constraint check, it auto generates the index.


 Index – it is of two types – Cluster and Non-Cluster index
 Cluster – it is only one in one table.
 Non-Cluster – these can be multiple up to 249.

 VARCHAR (8000-max character) – stores up to sky value and also use for store the non-Unicode values.
 VARCHAR(MAX) (2GB max)

 NVARCHAR (4000 max character) – use for stores the Unicode values. Means there are include the
different language character. [N -> national]
 NVARCHAR (2GB)

 CHAR – Fixed length as the requirement of the user.


Exa- char(5)
K r i s h
R a m

 VHARCHAR (variable length) – it always takes +1 or +2 extra bytes after fixed length.
 It takes +1 extra bytes when the size of VARCHAR is from 0 – 255.
 It takes +2 extra bytes when the size of VARCHAR is greater than >255.
 In MS SQL SERVER the max no. of column in table are 1024.
 1024 column are called non-sparse column.
 Above the 2008 version of MS SQL Server, the sparse column introduced with max column size 30,000.
(The spares column is used when the max no. of column is null. It auto reduces the size of column/ table up
to 40%.)

[Class is reuse for reusability


Sealed class never be inherited]

 Web.config --- XML base file ( it is use for connection string because this file is no need for complication)

<connectionStrings> [key name (it may be anything)]

<add name=”cn” connectionString=” server = dev\sqlexpress; database = dbemply; integrated security = true” />

</connectionStrings>

Server name database name [ window authentication

(in SQL authentication name & password are write)]

using System.Data;
using System.Data.SqlClient; (work only with MS SQL Server)
using System.Configuration;

public partial class index : System.Web.UI.Page


{

SqlConnection con = new SqlConnection();

protected void Page_Load(object sender, EventArgs e)


{
[non-static members are access with object]

con.ConnectionString = ConfigurationManager.ConnectionStrings["stdKeyId"].ConnectionString;

if (con.State == ConnectionState.Closed)
{
con.Open(); enumeration (constant type)
}
}

protected void saveBtn_Click(object sender, EventArgs e)


{

[use for data manipulation]

SqlCommand cmd = new SqlCommand();


cmd.CommandText = "insert student_table values(@stdid,@stdname,@stdclass,@stdsub)";

[inline queries]
cmd.Connection = con;
cmd.Parameters.AddWithValue("@stdid", TxtId.Text);
cmd.Parameters.AddWithValue("@stdname", TxtName.Text);
cmd.Parameters.AddWithValue("@stdclass", TxtClass.Text); [jitne parameter hote hai
utne hi type honge yanha]
cmd.Parameters.AddWithValue("@stdsub", TxtSub.Text);
cmd.ExecuteNonQuery();
cmd.Dispose(); [it free the resource of the SQL Command]
TxtId.Text = “ “;  not use the space because space work as character.

TxtId.Text = string.Empty;
TxtName.Text = string.Empty;
TxtClass.Text = string.Empty;
TxtSub.Text = string.Empty;
TxtId.Focus();
Display_Refactor();

private void Display_Refactor()


{
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "select * from student_table";
cmd.Connection = con;
SqlDataReader stdDataReader;

[use to display the data, it can only read and forward the data, it is the
fastest way of data retrieve process]

stdDataReader = cmd.ExecuteReader();
ListBox1.DataTextField = "stdName";
ListBox1.DataValueField = "stdId";

[only for write, not for display]

[In Listbox there are only show 2 columns]

ListBox1.DataSource = stdDataReader;
ListBox1.DataBind();
stdDataReader.Close();
cmd.Dispose();
}

ADO.NET is a data access technology from the Microsoft. NET Framework that provides communication between
relational and non-relational systems through a common set of components. ADO.NET is a set of computer software
components that programmers can use to access data and data services from a database.

AutoPostBack property should be true

protected void
ShowList_SelectedIndexChanged
(object sender, EventArgs e)
{
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "select * from teacher_table where
TeacherID = @teachid";
cmd.Connection = conn;
use for run the SQL command
cmd.Parameters.AddWithValue("@teachid",
ShowList.SelectedValue);
SqlDataReader teachReader = cmd.ExecuteReader();
iska reference yanha store hoga
if (teachReader.HasRows)
{
teachReader.Read();
TextId.Text = teachReader["TeacherID"].ToString();
TextName.Text = teachReader["TeacherName"].ToString();
TextSub.Text = teachReader["TeacherSubject"].ToString();
TextDep.Text = teachReader["TeacherDept"].ToString();

}
teachReader.Close();
cmd.Dispose();
}

protected void
Delete_btn_Click(object
sender, EventArgs e)
{
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "delete from student_table where
stdRoll=@stdid";
cmd.Connection = conn;
cmd.Parameters.AddWithValue("@stdid", Textroll.Text);
cmd.ExecuteNonQuery();
cmd.Dispose();
dis_refactor();
clr_refactor();
}
The DELETE statement is used when we want to remove some or all of the records from the table, while the
TRUNCATE statement will delete entire rows from a table.

 Types of parameters in Stored Procedure in MS SQL Server database: -


1) Input – it is also by default and use only for input.
2) Output – only for return/ output.
3) Input-Output – Pass the value and retrieve the data.
4) Return value- for output.
Database

 Master table - The table where the data enter/ change sometimes only.
 Transition table - The table where the data change frequently.
 Exa-
 Country table, state table, city table, registration code.
SELECT regnam,regadd,regeml,cntnam,stanam,ctynam from tbreg,tbcty,tbsta,tbcnt where
regctycod,regctycod = ctycod and ctystacod = stacod and statntcod = cntcod

Exa2- tbdep dno (int(primary key))


dname V(50)

tbdsg dsgcod int(pk)


dsgnam V(500)

tbemployee empno int(pk)


ename V(50)
eadd V(50)
esal int
edno int(forigin key) – tbdep(dno)
edsgcod int(FK) – tbdsg(dsgcod)

MVC (Architecture, Design pattern)

2- Tier Architecture => Database Tier Presentation Tier

3-Tier Architecture => Database Tier Middle Tier/Business Tier Presentation Tier
(Use OOPs concept)

 Model (Classes, Database Tier), Controller (Classes, Request handler), View ( UI)
 It follows the loosely coupled technique.
 There are use HTML helpers.

MVC with Database using Entity Framework


 Database First (old)
 Code First (New)  create database through coding

1) Tools  NuGet Package manager  Browse  Entity Framework  Install


Global.asas
 It is used to manage application-level events and session level events.
 Firstly create connection string in Web.config
<connectionStrings>

<add name="conString" connectionString="server=.\sqlexpress;database=student_database; integrated


security=true" providerName="System.Data.SqlClient"/>

</connectionStrings>

 Model  add class  Student.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace mvc_database_create_edit.Models
{
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public string Class { get; set; }
public int Age { get; set; }
}
} use for write only

Use for read only

 Model  add class  ApplicationContext.cs

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;

namespace mvc_database_create_edit.Models
{
public class ApplicationContext:DbContext
{
public ApplicationContext() :base("ConString")
{
}
public DbSet<Student> Students { get; set; }
}
}

 Tools  NuGet Package Manager  Console

(it maybe anything)

 Controller  StudentCtrController

using mvc_database_create_edit.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace mvc_database_create_edit.Controllers
{
public class StudentCtrController : Controller
{
// GET: StudentCtr (it’s value change only in constructor, but const value don’t change
anywhere)

private readonly ApplicationContext context;


public StudentCtrController()
{
context = new ApplicationContext();
}
public ViewResult Index()
{

It is a single line declaration and initialization variable and can store any type of data. It is
use only in local members and decide the data types at compile time.

var studentList = context.Students.ToList();


return View(studentList);
}
public ViewResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(Student student)
{
if (student == null) return HttpNotFound();
context.Students.Add(student);
context.SaveChanges();
return RedirectToAction("Index");
}
public ActionResult Edit(int id)
{
var studentId = context.Students.Find(id); (it find only primary key, it not work with
multiple columns and work only with one record)

if(studentId == null) return HttpNotFound();


return View(studentId);
}
[HttpPost]
public ActionResult Edit(Student student)
{
if (student == null) return HttpNotFound();
var studentfromTb = context.Students.Find(student.Id);
if (studentfromTb == null) return HttpNotFound();
studentfromTb.Name = student.Name;
studentfromTb.Class = student.Class;
studentfromTb.Age = student.Age;
context.SaveChanges();
return RedirectToAction(nameof(Index));
}

public ActionResult Details(int? id)


{
var studentId = context.Students.Find(id);
if(studentId == null) return HttpNotFound();
return View(studentId);
}
public ActionResult Delete(int id)
{
var studentId = context.Students.Find(id);
if (studentId == null) return HttpNotFound();
return View(studentId);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(int id,Student student)
{
var studentId = context.Students.Find(id);
if(studentId==null) return HttpNotFound();
context.Students.Remove(studentId);
context.SaveChanges();
return RedirectToAction(nameof(Index));
}
public ActionResult Delete_Rec(int id)
{
var studentId = context.Students.Find(id);
if (studentId == null) return HttpNotFound();
context.Students.Remove(studentId);
context.SaveChanges();
return RedirectToAction(nameof(Index));
}

}
}
 View (auto generate folder when the controller is created)  add  view (same name of view as the Action name
(Index))  Index  Template (List)  modelClass

(only one model add in a page)


@model IEnumerable<mvc_database_create_edit.Models.Student>

@{
ViewBag.Title = "Index";
}

<h2 class="text-primary">List of Students</h2>

<p>
@Html.ActionLink("Create New", "Create")
</p>
@if (!Model.Any())
{
<p class="text-danger">No Record Found!</p>
}
else
{
<table class="table">
<thead>
<tr>
<th> (lambda expression)
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Class)
</th>
<th>
@Html.DisplayNameFor(model => model.Age)
</th>
<th></th>
</tr>
</thead>
<tbody> (it decide the data type of item at compile time)
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Class)
</td>
<td>
@Html.DisplayFor(modelItem => item.Age)
</td>
<td
@Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
@Html.ActionLink("Details", "Details", new { id = item.Id }) |
@Html.ActionLink("Delete", "Delete", new { id = item.Id })
</td>
</tr>
}
</tbody>
</table>
}

Routes

 Types of Routing in MVC –


1) Conventional Routing (old) –

2) Attribute base Routing (new) –

 For using the attribute base routing, firstly add this line in the RouteConfig file.

 This line is written on the action method where the routing applies. This is written in Controller file.
 Route is just a pattern.

 This is the prefix for route pattern. It must be included in front of route and it written in starting at
controller.
 These are the constraints which are used in attributes base routing. Where {a} and {b} are parameters.

New Application
Step-:

1) Install Entity Framework

2) Make a connection string

3) Create a model file  add class  {Student}


4) Add new folder in Application with name {Data}  add class  ApplicationDbContext

5) Add migration  Enable-migrations  add-migration initLoad  update-database

6) Apply bootstrap theme

7) Add Controller 
8) Make Action Link in View Shared 

9) Index.cshtml

10) Add  View  Create.cshtml 


11) Now create a” Save” button and “section script” in Create.cshtml from BundleConfig.cs

12) Add validation message and Display value in Student class 

13) Write the coding in controller of server-side validation and show the created data in table 
Server-side validation

14) Create a link in Create.cshtml for go to backlist


@Html.ActionLink("Go to List!","Index")
15) Now create a @using (Html.BeginForm("AddNewStudent","StudentCtl")), it is use when the
Action name and View name are different. Action Name Controller Name

16) Now write the Code of Edit Action

17) Now create the Edit View and also include the script section and Back to List link 
18) Write the Update code with E-mail validation check-

It comes from Database

It comes from View

19) Write the code of Details Action and add its View 

View
Ternary Operator (this condition can be
performed by the simple If Else condition
as shown below image)

20) Write the code of Delete Action 


Custom Validation

21) Write click on Project Name and add a new folder  CustomValidation  add class  AgeValidation 

22) Write the code of Age Validation in class AgeValidation and use it in Student class

23) Write the validation for email  add class  CustomValidation  EmailValidation and its code and use in
Student class 
Layout

24) Download the bootstrap theme and paste these in Content Folder

25) Now make the bundle of these file into BundleConfig.cs

26) Now copy the layout.cshtml file 2 time in same place and change the name of file and also change the
name of @Styles.Render("~/MyContent1/css"),@Styles.Render("~/MyContent2/css")
same as the name of BundleConfig file.

27) Now go to View  StudentCtl  Index.cshtml  add layout path

28) This path and the bootstrap file name add where there you want to apply the bootstrap theme

29) We also can change the theme of all the project 

Partial View

30) The Partial View is created once in Shared View and use anywhere in the project 
Go to Shared View  Right click  add view choose partial view 
Name must be start with

it represents the global representation in the project, because it can


be call/use anywhere in the project

31) Write the code at here which we want to write many times in the project 
Exa. 
Now call this file anywhere with 3 types 
i) In Index.cshtml  @Html.Partial("_PartialView")
ii) In Index.cshtml  @{ Html.RenderPartial("_PartialView");}
iii) Make a Action/Method in HomeController and call this file at here 

iv) Now call the Action name at anywhere  @Html.Action("LoadPartialView")

New MVC Project(MVCentityFrameworkNewProject)

Step: -
1) Install Entity Frmaework
2) Make a connection String
<connectionStrings>
<add name="conStr" connectionString="server=.\sqlexpress; database=MVCDbNewProject; integrated
security=true" providerName="System.Data.SqlClient"/>
</connectionStrings>

3) Models  Add Class  Department

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MVCentityFrameworkNewProject.Models
{
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
}
}

4) Add another class in Models  Designation

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MVCentityFrameworkNewProject.Models
{
public class Designation
{
public int Id { get; set; }
public string Name { get; set; }
}
}

5) Add also Another Class in Models  Employee

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;

namespace MVCentityFrameworkNewProject.Models
{
public class Employee
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Address { get; set; }
public int Salary { get; set; }
[Required]
[Display(Name="Department")]
public int DepartmentId {get; set;}
public Department Department { get; set; }
[Display(Name = "Designation")]
public int DesignationId { get; set; }
public Designation Designation { get; set; }
}
}

6) Add new folder Data in project

Add a new class in Data Folder of name ApplicationDbContext,


In this class add the Department, Designation and Employee 

using MVCentityFrameworkNewProject.Models;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Drawing.Printing;
using System.Linq;
using System.Web;

namespace MVCentityFrameworkNewProject.Data
{
public class ApplicationDbContext:DbContext
{
public ApplicationDbContext(): base("conStr")
{

}
public DbSet<Department> Departments { get; set; }
public DbSet<Designation> Designations { get; set; }
public DbSet<Employee> Employees { get; set; }
}
}

7) Add migration, run these commands one by one 

 enable-migrations
 add-migrations initLoad
this command creates a file 

namespace MVCentityFrameworkNewProject.Migrations
{
using System;
using System.Data.Entity.Migrations;

public partial class initLoad : DbMigration


{
public override void Up()
{
CreateTable(
"dbo.Departments",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(),
})
.PrimaryKey(t => t.Id);

CreateTable(
"dbo.Designations",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(),
})
.PrimaryKey(t => t.Id);

CreateTable(
"dbo.Employees",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(nullable: false),
Address = c.String(nullable: false),
Salary = c.Int(nullable: false),
DepartmentId = c.Int(nullable: false),
DesignationId = c.Int(nullable: false),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.Departments", t => t.DepartmentId, cascadeDelete: true)
.ForeignKey("dbo.Designations", t => t.DesignationId, cascadeDelete: true)
.Index(t => t.DepartmentId)
.Index(t => t.DesignationId);

it makes the code able for that when the data change in the parent class then the child data will
be automatically change

public override void Down()


{
DropForeignKey("dbo.Employees", "DesignationId", "dbo.Designations");
DropForeignKey("dbo.Employees", "DepartmentId", "dbo.Departments");
DropIndex("dbo.Employees", new[] { "DesignationId" });
DropIndex("dbo.Employees", new[] { "DepartmentId" });
DropTable("dbo.Employees");
DropTable("dbo.Designations");
DropTable("dbo.Departments");
}
}
}

 update-database

8) Now for Enter the dummy/raw data into the database of Department and
Designation table, run a empty migration command with any name
 add-migration addDatatoDb

This command creates a file and, in this file, there are write some SQL
command for insert the dummy data 
namespace MVCentityFrameworkNewProject.Migrations
{
using System;
using System.Data.Entity.Migrations;

public partial class addDefaultValue : DbMigration


{
public override void Up()
{
// Department
Sql("insert Departments values('Account')");
Sql("insert Departments values('Sales')");
Sql("insert Departments values('Marketing')");

// Designation
Sql("insert Designations values('ProgramManager')");
Sql("insert Designations values('TechinicalLeader')");
Sql("insert Designations values('Programer')");
}

public override void Down()


{
}
}
}
 Now update again database with  update-database

9) Now add controller  EmployeeCtl 


using MVCentityFrameworkNewProject.Data;
using MVCentityFrameworkNewProject.Models;
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Drawing.Printing;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MVCentityFrameworkNewProject.Controllers
{
public class EmployeeCtlController : Controller
{
private readonly ApplicationDbContext context;
public EmployeeCtlController()
{
context = new ApplicationDbContext();
}

// Disposing the Context Resources


protected override void Dispose(bool disposing)
{
context.Dispose();
}
// GET: EmployeeCtl
public ActionResult Index()
{
//Create List
var employeeList = context.Employees.Include(e => e.Department).Include(e =>
e.Designation).ToList();
return View(employeeList);

This function is use for join the multiple tables

10) Now add the link at Navbar in _Layout.cshtml 

<li>@Html.ActionLink("Employee List", "Index", "EmployeeCtl")</li>

11) Now add the view of Index  Indec.cshtml 

@model IEnumerable<MVCentityFrameworkNewProject.Models.Employee>

<h2 class="text-center text-primary">Employee Data </h2>


@Html.ActionLink("Add New Employee", "Upsert", "EmployeeCtl", new { @class="btn btn-success" })

@if (!Model.Any())
{
<h3 class="text-danger">No record found!</h3>
}
else
{
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Address</th>
<th>Salary</th>
<th>Departments</th>
<th>Designation</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach (var employee in Model)
{
<tr>
<td>@employee.Name </td>
<td>@employee.Address </td>
<td>@employee.Salary </td>
<td>@employee.Department.Name </td>
<td>@employee.Designation.Name </td>
<td>
@Html.ActionLink("Edit", "Upsert", "EmployeeCtl",new { id = employee.Id }, new { @class = "btn btn-primary" })
@Html.ActionLink("Details", "Details", "EmployeeCtl", new { @class = "btn btn-primary" })
<input type="submit" value="Delete" class="btn btn-danger" onclick="return confirm('Want to Delete')" />
</td>
</tr>
}

</tbody>
</table>
}

12) Now create an Action of name Upsert in EmployeeCtl

public ActionResult Upsert(int? id)


{ this sign(?) is use for insert the null value in int type

ViewData["depList"] = context.Departments.ToList();
ViewData["desList"] = context.Designations.ToList();

(It works as to pass the data from Action to View and get data from multiple tables and
there is need for type casting in its view or where the table data show/put/post)

Employee employee = new Employee();

// Create
if (id == null) return View(employee);

//Edit
employee = context.Employees.Include(e => e.Department).Include(e =>
e.Designation).FirstOrDefault(e => e.Id == id);
if (employee == null) return HttpNotFound();
return View(employee);
}

13) Now create the view of Upsert Action 

@model MVCentityFrameworkNewProject.Models.Employee
@using MVCentityFrameworkNewProject.Models (this line is write because we use the 2 different model/table
(Department,Designation) in the below code )
@{
ViewBag.Title = "Upsert";
var title = Model.Id != 0 ? "Edit Employee Details" : "Add New Employee";
}

<h2 class="text-primary text-center">@title</h2>


<hr />

@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true, "", new { @class = "text text-danger" })
<div class="row">
<div class="form-group">
@Html.LabelFor(m => m.Name)
@Html.TextBoxFor(m => m.Name, new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.Name, "", new { @class = "text-danger" })
</div>
<div class="form-group">
@Html.LabelFor(m => m.Address)
@Html.TextBoxFor(m => m.Address, new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.Address, "", new { @class = "text-danger" })
</div>
<div class="form-group">
@Html.LabelFor(m => m.Salary)
@Html.TextBoxFor(m => m.Salary, new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.Salary, "", new { @class = "text-danger" })
</div>
<div class="form-group">
@Html.LabelFor(m=>m.DepartmentId)
@Html.DropDownListFor(m=>m.DepartmentId,new SelectList(ViewData["depList"] as List<Department>,
"Id","Name"),"Select Your Department", new {@class="form-control"})
@Html.ValidationMessageFor(m=>m.DepartmentId,"", new {@class="text-danger"})
</div>

(This key comes from the Upsert Action)

<div class="form-group">
@Html.LabelFor(m => m.DesignationId)
@Html.DropDownListFor(m => m.DesignationId, new SelectList(ViewData["desList"] as List<Designation>,
"Id", "Name"), "Select Your Designation", new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.DesignationId, "", new { @class = "text-danger" })
</div>

<div class="form-group">
<button type="submit" class="btn btn-success">
@(Model.Id != 0 ? "Update" : "Save")

(this ternary condition is use for auto select the name of button (Save/Update), when the id is
0 then display the “Save” else “Update” button )
</button>
</div>
</div>
}
@Html.ActionLink("Back to List!","Index")
@section scripts{
@Scripts.Render("~/bundles/jqueryval")
}

14) Now write the code/create the action for Save and Update into
single Action 

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upsert(Employee employee)
{
if (employee == null) return HttpNotFound();
if (!ModelState.IsValid)  (server side validation)
{
ViewData["depList"] = context.Departments.ToList();
ViewData["desList"] = context.Designations.ToList();
View(employee);
}

// Save
if (employee.Id == 0) context.Employees.Add(employee);
else
{
//Update
var employeeInDb = context.Employees.Find(employee.Id);
if (employeeInDb == null) return HttpNotFound();
employeeInDb.Name = employee.Name;
employeeInDb.Address = employee.Address;
employeeInDb.Salary = employee.Salary;
employeeInDb.DepartmentId = employee.DepartmentId;
employeeInDb.DesignationId = employee.DesignationId;
}
context.SaveChanges();
return RedirectToAction(nameof(Index));
}

15) Now we use the ViewBag instead of ViewData in Upsert Action


Note: we use ViewBag only for Designation data.
if (!ModelState.IsValid)
{
ViewData["depList"] = context.Departments.ToList();
//ViewData["desList"] = context.Designations.ToList();
ViewBag.desList = context.Designations.ToList();
View(employee);
}

16) After use the ViewBag we need to some changes in View


(Upsert.cshtml) 

<div class="form-group">
@Html.LabelFor(m => m.DesignationId)
@*@Html.DropDownListFor(m => m.DesignationId, new SelectList(ViewData["desList"] as List<Designation>,
"Id", "Name"), "Select Your Designation", new { @class = "form-control" })*@
@Html.DropDownListFor(m => m.DesignationId,new SelectList(ViewBag.desList,"Id","Name"),"Select Your
Designation", new {@class="form-control"})
@Html.ValidationMessageFor(m => m.DesignationId, "", new { @class = "text-danger" })
</div>

In ViewBag there is no need for Type Casting and also no need for include the namespace at
above but in ViewData there is need for include the namespace(@using
MVCentityFrameworkNewProject.Models) and the type casting.

17) Write the code of Details Action 

public ActionResult Details(int id)


{
var empInDb =
context.Employees.Include(e=>e.Department).Include(e=>e.Designation).FirstOrDefault(e=>e.Id == id);
if(empInDb == null) return HttpNotFound();
return View(empInDb);
}

18) Now create the view of Details Action 

@model MVCentityFrameworkNewProject.Models.Employee
@{
ViewBag.Title = "Details";
}

<h2 class="text-primary text-center">Details of Employee</h2>


<table class="table table-bordered table-hover">
<thead>
<tr>
<th>Name</th>
<th>Address</th>
<th>Salary</th>
<th>Department</th>
<th>Designation</th>
</tr>
</thead>
<tbody>
<tr>
<td>@Model.Name</td>
<td>@Model.Address</td>
<td>@Model.Salary</td>
<td>@Model.Department.Name</td>
<td>@Model.Designation.Name</td>
</tr>
</tbody>
</table>
@Html.ActionLink("Back to List!","Index")
<br />
@Html.ActionLink("Edit", "Upsert", new {id=Model.Id})

19) Now add the Id in Details button in Index.cshtml 

@Html.ActionLink("Details", "Details", "EmployeeCtl", new { id = emp.Id }, new { @class = "btn btn-primary" })

20) Now write the code of Delete Action 

public ActionResult Delete(int id)


{
var empInDB = context.Employees.Find(id);
if (empInDB == null) return HttpNotFound();
context.Employees.Remove(empInDB);
context.SaveChanges();
return RedirectToAction(nameof(Index));
}

21) Now add the Delete button view code in Index.cshtml with using the
Html.BeginForm 

@model IEnumerable<MVCentityFrameworkNewProject.Models.Employee>

<h2 class="text-center text-primary">Employee Data </h2>


@Html.ActionLink("Add New Employee", "Upsert", "EmployeeCtl", new { @class = "btn btn-success" })
<hr />
@if (!Model.Any())6
{
<h3 class="text-danger">No record found!</h3>
}
else
{
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Address</th>
<th>Salary</th>
<th>Departments</th>
<th>Designation</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach (var emp in Model)
{
using (Html.BeginForm("Delete", "EmployeeCtl", new { id = emp.Id }))
{
<tr>
<td> @emp.Name </td>
<td> @emp.Address </td>
<td> @emp.Salary </td>
<td> @emp.Department.Name </td>
<td> @emp.Designation.Name </td>
<td>
@Html.ActionLink("Edit", "Upsert", "EmployeeCtl", new { id = emp.Id }, new { @class
= "btn btn-primary" })
@Html.ActionLink("Details", "Details", "EmployeeCtl", new { id = emp.Id }, new {
@class = "btn btn-primary" })
<input type = "submit" value = "Delete" class="btn btn-danger" onclick="return
confirm('Want to Delete?')" />
</td>
</tr>
}

</tbody>
</table>
}

Action Selector List: -


i) ActionName  It is use when we want to change the name of action at
router but not want to change the name of Action in really, but if we
want to change the name of Action in really then we must be pass the
name of first view in View() and also pass it in BeginForm().
[HttpPost]
[ActionName("Create")]
public ActionResult Save()
{
return View("Create");
}

ii) NoAction  It is use when disable the Action in Actually, because in


a project there are multiple views/actions and there is some in
working then this NoAction is used.

iii) ActionVerbs  The ActionVerbs selector is to handle different type of Http


requests, like: HttpPost,HttpGet,HttpPut,HttpDelete etc.
Ecommerce Online Shopping Project

Steps: -
1) New Project 
2) ASP.NET CORE MVC, Web App 

3) Ecomm_Project2 

4) Choose the Framework version and Authentication type 

5) After Project Create, these files and folder are created 

6) Now go to the Fie Option and Add  New Project

7) Now choose the Class Library 


8) Now write the name of class 

9) Now choose the version of Framework and  Create 

10) There are create some file and delete the Class1.css file 

11) Now again add the new Class  Go to File  Add  New Project  Ecomm_Project2.DataAccess

12) Again, Delete the Class1.cs file 

13) Again, add a new class and Delete the Class1.cs file 
14) Now clean the all projects and build them by press the right click on the projects 

15) Now go to main project and add Project Reference (because the files are added from another
project) 

16) Now install the projects ( MS.EntityFrameworkCore and SqlServer and Tools )
17)

18) Now Cut the Models folder from main project and paste it in Ecomm_Project2.Models 

19) Now change the name of Models in Ecomm_Project2.Models to ViewModels 

20) Now Clean and Build the Ecomm_Project2.Models and main Project 
21) Now cut the Data folder from main project and paste it in Ecomm_Project2.DataAccess 

22) Now delete the Migration folder from the Ecomm_Project2.DataAccess 


23) Now add the namespace of ErrorViewModel.cs in Ecomm_Project2.Models 

24) Now check the namespace and other error in ApplicationDbContext in Ecomm_Poject2.DataAccess
and correct them 

25) Now check each projects’ error by Build and solve these errors.

26) During the Build the projects there is error find in Main project,Startup.cs file, Like 
27) Add the namespace of these file and you can remove these errors.

28) Again, Build the main project and we find an error more and build the project again and agin
till the all error are not remove/solve 

29) There is an error in HomeController 

30) Hover on this error and add the namespace 

31) Again build the main project and there are show some error 
32) Go to Ecomm_Project2.Models  ViewModels  ErrorViewModel.cs 

Copy this namespace and paste it in 

33) Now again Build the main project and there is no any error in project 

34) Add the Database path in appsettings.json and there can do some changes 

35) Now go to the Startup.cs 

36) Add connection string 

37) Now if we want to change the theme, then go to Bootswatch website and choose a version 4
theme and use it in our project by replace old css file with new css file 
Change the name of ~/lib/bootstrap/dist/css/bootstrap.min.css to
~/lib/bootstrap/dist/css/bootstrap.css in _Layout.cshtml 

38) Now add new area in Area folder of main project 

39) Now delete the two folder Data and Models from Area 
40) Now cut the HomeController.cs from Controllers and paste it into the Customer  Controllers

41) Now delete the Controllers folder from main project.

42) Now cut the Home folder from View folder of main project and paste it into the Areas 
Customer  Views 

43) Now go to Startup.cs file of main project and add the name of area in the it 
44) There is no path find so for this problem there can be add Area name in HomeController of
Area 

45) Now set a path in ScaffoldingReadMe.txt file of main project 

46) Now for show the output in browser there are copy two files from Views  Shared 
47) Now add new Admin Area in Area folder of main project 

48) Now delete these two folders 

49) Now copy the two files of main project  Views  Shared  into Areas  Admin 

50) Now add new Category.cs Class in Ecomm_Project2.Models and add Id, Name in Category.cs class

51) Now same a new class add in Ecomm_Project2.Models of name CoverType and Id, Name in it 

52) Now add the project reference in Ecomm_Project2.DataAccess 

53) Add Category and CoverType List in ApplicationDbContext 


54) Cut the Migration folder and paste it into Data folder in Ecomm_Project2.DataAccess 

55) Run migration command  add-migration initLoad2, update-database in


Ecomm_project2.DataAccess project 

56) Now go to the Ecomm_project2.DataAccess and add new folder of name Repository 

57) Now again add a new folder in Repository folder of name IRepository 

58) Now add a new class in IRepository folder of name IRepository.cs and choose the interface
during the create this class 
Make it public from internal

59) Now write the Add, Find, Details and Remove code in IRepository class 

60) Now add a new class in Repository folder of name Repository.cs in Ecomm_project2.DataAccess

Write the below code in Repository.cs class 


using Ecomm_Project2.DataAccess.Data;
using Ecomm_Project2.DataAccess.Repository.IRepository;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace Ecomm_Project2.DataAccess.Repository
{
public class Repository<T> : IRepository<T> where T : class
{
private readonly ApplicationDbContext _context;
internal DbSet<T> dbSet;
public Repository(ApplicationDbContext context)
{
_context = context;
dbSet = _context.Set<T>();
}

public void Add(T entity)


{
dbSet.Add(entity);
}

public T FirstOrDefault(Expression<Func<T, bool>> filter = null, string includeProperties = null)


{
IQueryable<T> query = dbSet;
if (filter != null)
query = query.Where(filter);
if(includeProperties != null)
{
foreach( var includeProp in includeProperties.Split(new char[] {','},
StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProp);
}
}
return query.FirstOrDefault();
}

public T Get(int id)


{
return dbSet.Find(id);
}

public IEnumerable<T> GetAll(Expression<Func<T, bool>> filter = null,


Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, string includeProperties = null)
{
IQueryable<T> query = dbSet;
if (filter != null)
query = query.Where(filter);
if (includeProperties != null)
{
foreach (var includeProp in includeProperties.Split(new char[] { ',' },
StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProp);
}
}
if(orderBy != null)
return orderBy(query).ToList();
return query.ToList();
}

public void Remove(T entity)


{
dbSet.Remove(entity);
}

public void Remove(int id)


{
// var entity = dbSet.Find(id);
// dbSet.Remove(entity);
var entity = Get(id);
Remove(entity);
}

public void RemoveRange(IEnumerable<T> entitiy)


{
dbSet.RemoveRange(entitiy);
}
}
}

61) Now add a new class of Interface type in subfolder of Repository  IRepository of name
ICategoryRepository in in Ecomm_project2.DataAccess project 
62) Now write the Update code in new created interface class ICategoryRepository 

using Ecomm_Project2.Models.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.DataAccess.Repository.IRepository
{
public interface ICategoryRepository: IRepository<Category>
{
void Update(Category category);
}
}

63) Now add a new class in Repository folder of name CategoryRepository 

Write this update code in CategoryRepository class 

using Ecomm_Project2.DataAccess.Data;
using Ecomm_Project2.DataAccess.Repository.IRepository;
using Ecomm_Project2.Models.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.DataAccess.Repository
{
public class CategoryRepository : Repository<Category>, ICategoryRepository
{
private readonly ApplicationDbContext _context;
public CategoryRepository(ApplicationDbContext context) : base(context)
{
_context = context;
}
public void Update(Category category)
{
_context.Update(category);
}

}
}

64) Now again add a new Interface class in IRepository folder of name ICoverTypeRepository 

Write this code in this Interface class 


using Ecomm_Project2.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.DataAccess.Repository.IRepository
{
public interface ICoverTypeRepository : IRepository<CoverType>
{
void Update(CoverType coverType);
}
}

65) Now add a new class in Repository folder of name CoverTypeRepository 


Write this code in this class 
using Ecomm_Project2.DataAccess.Data;
using Ecomm_Project2.DataAccess.Repository.IRepository;
using Ecomm_Project2.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.DataAccess.Repository
{
public class CoverTypeRepository : Repository<CoverType>, ICoverTypeRepository
{
private readonly ApplicationDbContext _context;
public CoverTypeRepository(ApplicationDbContext context) : base(context)
{
_context = context;
}

public void Update(CoverType coverType)


{
_context.Update(coverType);
}
}
}

66) Now add the CategoryRepostory and CoverTypeRepository in Startup.cs class 

67) Now add the new Interface class type IUnitOfWork in IRepository folder 

Write the code in IUnitOfWork Interface class 


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

namespace Ecomm_Project2.DataAccess.Repository.IRepository
{
public interface IUnitOfWork
{
ICategoryRepository Category { get; }
ICoverTypeRepository CoverType { get; }
void Save();
}
}

68) Now add the new UnitOfWork class in Repository folder 

Write the Save and Database connection code in this class 


using Ecomm_Project2.DataAccess.Data;
using Ecomm_Project2.DataAccess.Repository.IRepository;

namespace Ecomm_Project2.DataAccess.Repository
{
public class UnitOfWork : IUnitOfWork
{
private readonly ApplicationDbContext _context;
public UnitOfWork(ApplicationDbContext context)
{
_context = context;
Category = new CategoryRepository(_context);
CoverType = new CoverTypeRepository(_context);
}
public ICategoryRepository Category { get; private set; }

public ICoverTypeRepository CoverType { get; private set; }


public void Save()
{
_context.SaveChanges();
}
}
}

69) Now comment these two lines in Startup.cs file and add a new line in it 
70) Now add a new CategoryController controller in Area  Admin  Controller 

Write some code in this controller 


using Ecomm_Project2.DataAccess.Repository.IRepository;
using Microsoft.AspNetCore.Mvc;

namespace Ecomm_Project2.Areas.Admin.Controllers
{
[Area("Admin")]
public class CategoryController : Controller
{
private readonly IUnitOfWork _unitOfWork;
public CategoryController(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public IActionResult Index()
{
return View();
}
}
}

71) Add View of Index Action 


72) Add a dropdown list in the Navbar at _Layout.cshtml file 

<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-
action="Privacy">Privacy</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#" role="button"
aria-haspopup="true" aria-expanded="false">Content Management</a>
<div class="dropdown-menu">
@*<a class="dropdown-item" href="#">Action</a>*@
<a class="dropdown-item" asp-area="Admin" asp-controller="Category" asp-
action="Index" >Category</a>
<a class="dropdown-item" href="#">Another action</a>
<a class="dropdown-item" href="#">Something else here</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Separated link</a>
</div>
</li>

73) Now write the code of API in CategoryController.cs file 

#region APIs
[HttpGet]
public IActionResult GetAll()
{
var categoryList = _unitOfWork.Category.GetAll();
return Json(new { data = categoryList });
}
#endregion

74) Now right click on GetAll() function and choose Go To Implementation option 

75) Now write the code in Index.cshtml 

<div class="row">
<div class="col-9">
<h2 class="text-success">Category List</h2>
</div>
<div class="col-3">
<a asp-action="Upsert" class="btn btn-info">
New Category
</a>
</div>
</div>
<div class="bordern p-2 m-2">
<table id="tblData" class="table table-active tab-content table-hover table-striped">
<thead>
<tr>
<th>Name</th>
<th>Actions</th>
</tr>
</thead>
</table>
</div>

76) Now add a new JavaScript file of name category.js in main project  wwwroot  js  add 
New Item 
Now write the code in JSON form of API data in new create js file category.js file 
var dataTable;
$(document).ready(function () {
loadDataTable();

})
function loadDataTable() {
dataTable = $('#tblData').DataTable({
"ajax": { "url": "/Admin/Category/GetAll" },
"columns": [{
"data": "name", "width": "70%"
},
{
"data": "id", "render": function (data) {
return `
<div class="text-center">
<a href="/Admin/Category/Upsert/${data}" classs = "btn btn-info">
<i class="fas fa-edit"></li>
</a>
<a classs = "btn btn-danger" onclick=Delete("/Admin/Category/Delete/${data}")>
<i class="fas fa-trash-alt"></li>
</a>
</div>

`;
}
}
]
})
}

77) Now add the script section in Index.cshtml file 

@section scripts{
<script src="~/js/category.js"></script>
}

78) Now write the code of Upsert in CategoryController.cs 

public IActionResult Upsert(int? id)


{
// Create
Category category = new Category();
if(id == null) return View(category);

// Edit
category = _unitOfWork.Category.Get(id.GetValueOrDefault());
if (category == null) return NotFound();
return View(category);
}

79) Now add the V iew of Upsert 


80) Now write the code of add a new category in Upsert.cshtml 

@model Ecomm_Project2.Models.Category
@{
ViewData["Title"] = "Upsert";
var title = Model.Id != 0 ? "Edit Category" : "New Category";
var saveupdate = Model.Id != 0 ? "Update" : "Save";
}

<form method="post">
<div class="row">
<h2 class="text-primary">@title</h2>
</div>
<hr />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="col-8">
<div class="form-group row p-2 m-2">
<div class="col-4">
<label asp-for="Name"></label>
</div>
<div class="col-8">
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
</div>
<div class="form-group row p-2 m-2">
<div class="col-4 offset-4">
<button type="submit" class="btn btn-success form-
control">@saveupdate</button>
</div>
<div class="col-4">
<a asp-action="Index" class="btn btn-primary form-
control">Back to List</a>
</div>
</div>
</div>
</form>
@section scripts{
<partial name="_ValidationScriptsPartial" />
}

81) Now go to Shared folder and a new View in main Project 

<div class="row">
<div class="col">
<button type="submit" class="btn btn-info form-control">Create</button>
</div>
<div class="col">
<a asp-action="Index" class="btn btn-success form-control">
Back to List
</a>
</div>
</div>
82) Now again crate a new View in Shared folder 

<div class="row">
<div class="col">
<button type="submit" class="btn btn-info form-control">Update</button>
</div>
<div class="col">
<a asp-action="Index" class="btn btn-primary form-control">
Back to List
</a>
</div>
</div>

83) Now go to Upsert.cshtml file and use these Partial type view in it but firstly we comments
the before Save and Update button code 

Add Required in Category.cs and CoverType.cs file 

84) Now Run the Migration Commands 


85) Now write the Update and Delete code in CategoryController.cs file 

86) Now add a Sweet Alert message on delete button at category.js 

function Delete(url) {
swal({
text: "Delete Information !!",
title: "Want to delete data ?",
icon: "warning",
buttons: true,
dangerModel: true
}).then((willDelete) => {
if (willDelete) {
$.ajax({
url: url,
type: "DELETE",
success: function (data) {
if (data.success) {
toastr.success(data.message);
dataTable.ajax.reload();
}
else {
toastr.error(data.message);
}
}
})
}
})
}

87) Now add a new CoverType controller 

using
Ecomm_Project2.DataAccess.Repository.IRepository;
using Microsoft.AspNetCore.Mvc;
using System.Text.RegularExpressions;

namespace Ecomm_Project2.Areas.Admin.Controllers
{
[Area("Admin")]
public class CoverTypeController : Controller
{
private readonly IUnitOfWork _unitOfWork;
public CoverTypeController(IUnitOfWork
unitOfWork)
{
_unitOfWork = unitOfWork;
}
public IActionResult Index()
{
return View();
}
#region APIs
[HttpGet]
public IActionResult GetAll()
{
return Json(new { data = _unitOfWork.CoverType.GetAll() });
}
#endregion
}
}
88) Now add the View of Index in CoverTypeController 

<div class="row">
<div class="col-9">
<h2 class="text-success">Cover Type List</h2>
</div>
<div class="col-3">
<a asp-action="Upsert" class="btn btn-info">
New Cover Type &nbsp;
<i class='fas fa-plus'></i>
</a>
</div>
</div>
<div class="border p-2 m-2">
<table id="tblData" class="table table-hover table-striped">
<thead>
<tr>
<th>Name</th>
<th>Actions</th>
</tr>
</thead>
</table>
</div>
@section scripts{
<script src="~/js/covertype.js"></script>
}

89) Now add the Cover Type category in _Layout.cshtml 

90) Now add a new Item in js file and write code here 

<div class="row">
<div class="col-9">
<h2 class="text-success">Cover Type List</h2>
</div>
<div class="col-3">
<a asp-action="Upsert" class="btn btn-info">
New Cover Type &nbsp;
<i class='fas fa-plus'></i>
</a>
</div>
</div>
<div class="border p-2 m-2">
<table id="tblData" class="table table-hover table-striped">
<thead>
<tr>
<th>Name</th>
<th>Actions</th>
</tr>
</thead>
</table>
</div>
@section scripts{
<script src="~/js/covertype.js"></script>
}
91) Now write the code of View, Find Update and Insert in CoverTypeController.cs 

92) Now add the View of Upsert 

93) Now write the code of Upsert.cshtml of related to CoverType 

@model Ecomm_Project2.Models.CoverType
@{
ViewData["Title"] = "Upsert";
var title = Model.Id != 0 ? "Edit Item" : "New Cover Type";
var saveupdate = Model.Id != 0 ? "Update" : "Save";
}

<form method="post">
<div class="row">
<div class="col-10 border-bottom">
<h2 class="text-info">@title</h2>
</div>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="col-8">
<div class="form-group row p-3 m-4">
<div class="col-4 offset-4">
<label asp-for="Name"></label>
</div>
<div class="col-8">
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger" />
</div>
</div>
<div class="form-group row p-3 m-4">
@if (Model.Id != 0)
{
<partial name="_EditAndBackToListButton" />
}
else
{
<partial name="_CreateAndBackToListButton" />
}
</div>
</div>
</div>
</form>
@section scripts{
<partial name="_ValidationScriptsPartial" />
}

94) Now write the Delete code of CoverType in CoverTypeController.cs 

95) Now write the code of CoverType Delete button in covertype.js file using the sweet alert 

function Delete(url) {
swal({
text: "Delete Information !!",
title: "Want to delete data ?",
icon: "warning",
buttons: true,
dangerModel: true
}).then((willDelete) => {
if (willDelete) {
$.ajax({
url: url,
type: "DELETE",
success: function (data) {
if (data.success) {
toastr.success(data.message);
dataTable.ajax.reload();
}
else {
toastr.error(data.message);
}
}
})
}
})
}

96) Now add the store procedure in CoverType for data store.

97) Go to SQL server object explorer in View  right click on database  and find the store
procedure 
Now write the Store procedure command in it 

Same add all the other command at here like, update, delete and select and then update-database at
migration command 
98) Now run the migration command  update-database 

99) Now add a new class in Ecomm_Project2.Utility of name SD 

Now write the code for access the store procedure in SD class 

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

namespace Ecomm_Project2.Utility
{
public static class SD
{
// cover type store procedure
public const string Proc_GetCoverTypes = "GetCoverTypes";
public const string Proc_GetCoverType = "GetCoverType";
public const string Proc_CreateCoverType = "CreateCoverType";
public const string Proc_UpdateCoverType = "UpdateCoverType";
public const string Proc_DeleteCoverType = "DeleteCoverType";

}
}

100) Now add a new Interface type class ISP_CALL in IRepositiory folder 
101) Now write the following code 

using Dapper;
using Microsoft.EntityFrameworkCore.Storage.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.DataAccess.Repository.IRepository
{
public interface ISP_CALL : IDisposable
{
void Execute(string procedureName, DynamicParameters param = null);
T Single<T>(string procedureName, DynamicParameters param = null);
T OneRecord<T>(string procedureName, DynamicParameters param = null);
IEnumerable<T> List<T>(string procedureName, DynamicParameters param = null);
Tuple<IEnumerable<T1>, IEnumerable<T2>> List<T1, T2>(string procedureName, DynamicParameters param =
null);

}
}

Install this package when we write the code at here 

102) Now add a new class in Repository folder of name SP_CALL 

Now write the following code in this class 


using Dapper;
using Ecomm_Project2.DataAccess.Data;
using Ecomm_Project2.DataAccess.Repository.IRepository;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.DataAccess.Repository
{
public class SP_CALL : ISP_CALL
{
private readonly ApplicationDbContext _context;
private static string connectionString = "";
public SP_CALL(ApplicationDbContext context)
{
_context = context;
connectionString = _context.Database.GetDbConnection().ConnectionString;
}

public void Dispose()


{
_context.Dispose();
}

public void Execute(string procedureName, DynamicParameters param = null)


{
using (SqlConnection sqlCon = new SqlConnection(connectionString))
{
sqlCon.Open();
sqlCon.Execute(procedureName, param, commandType: CommandType.StoredProcedure);
}
}

public IEnumerable<T> List<T>(string procedureName, DynamicParameters param = null)


{
using (SqlConnection sqlCon = new SqlConnection(connectionString))
{
sqlCon.Open();
return sqlCon.Query<T>(procedureName, param, commandType: CommandType.StoredProcedure);
}
}

public Tuple<IEnumerable<T1>, IEnumerable<T2>> List<T1, T2>(string procedureName, DynamicParameters


param = null)
{
using(SqlConnection sqlCon = new SqlConnection(connectionString))
{
sqlCon.Open();
var result = SqlMapper.QueryMultiple(sqlCon, procedureName, param, commandType:
CommandType.StoredProcedure);
var item1 = result.Read<T1>();
var item2 = result.Read<T2>();
if(item1 != null && item2 != null)
return new Tuple<IEnumerable<T1>, IEnumerable<T2>>(item1, item2);
return new Tuple<IEnumerable<T1>, IEnumerable<T2>>(new List<T1>(),new List<T2>());
}
}

public T OneRecord<T>(string procedureName, DynamicParameters param = null)


{
using( SqlConnection sqlCon = new SqlConnection(connectionString))
{
sqlCon.Open();
var value = sqlCon.Query<T>(procedureName, param, commandType: CommandType.StoredProcedure);
return value.FirstOrDefault();
}
}

public T Single<T>(string procedureName, DynamicParameters param = null)


{
using (SqlConnection sqlCon = new SqlConnection(connectionString))
{
sqlCon.Open();
return sqlCon.ExecuteScalar<T>(procedureName,param,commandType: CommandType.StoredProcedure);
}
}
}
}
103) No w add the SP_ CALL and ISP_CALL in the Interface IUnitOWork.cs 

104) Now go to the UnitOfWork.cs and add this code of line in it 

105) Now go to CoverTypeController.cs file and write the code of Get, Update/Upsert and
Delete with store procedure type at here 
106) Now add a class in in Ecomm_Project2.Models of name Product 

Now write the following code at here 


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

namespace Ecomm_Project2.Models
{
public class Product
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
public string Description { get; set; }
[Required]
public string ISBN { get; set; }
public string Author { get; set; }
[Required]
[Range(1,10000)]
public double ListPrice { get; set; }
[Required]
[Range(1,10000)]
public double Price50 { get; set; }
[Required]
[Range(1,10000)]
public double Price100 { get; set; }
[Required]
[Range(1,10000)]
public double Price { get; set; }
[Display(Name ="Image Url")]
public string ImageUrl { get; set; }
[Display(Name ="Category")]
public int CategoryId { get; set; }
[Display(Name ="Cover Type")]
public int CoverTypeId { get; set; }
public CoverType CoverType { get; set; }
}
}
107) Now register this Product.cs class into Ecomm_Project2.DataAccess  Data 
ApplicationDbContext.cs file 

108) Now add migration and update the database  add-migration addProductTable

109) Now add a new Interface type class IProductRepository in IRepository folder 

Now write code of Update at here 


using Ecomm_Project2.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.DataAccess.Repository.IRepository
{
public interface IProductRepository : IRepository<Product>
{
void Update (Product product);
}
}

110) Now add a new class ProductRepository in Repository folder 

using Ecomm_Project2.DataAccess.Data;
using Ecomm_Project2.DataAccess.Repository.IRepository;
using Ecomm_Project2.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.DataAccess.Repository
{
public class ProductRepository : Repository<Product>, IProductRepository
{
private readonly ApplicationDbContext _context;
public ProductRepository(ApplicationDbContext context) : base(context)
{
_context = context;
}

public void Update(Product product)


{
_context.Update(product);
}
}
}

111) Now register/ add the the IProductRepository in IUnitOfWork 

112) Now add the interface in UnitOfWork.cs class 

113) Now add a new controller ProductController in Areas  Admin  Controllers 

Now write the Index code of Product Controller 

using Microsoft.AspNetCore.Mvc;
namespace Ecomm_Project2.Areas.Admin.Controllers
{
[Area("Admin")]
public class ProductController : Controller
{
public IActionResult Index()
{
return View();
}
}
}
114) Now add the Product Index at Navbar in _Layout.cshtml

115) Now add View of Index in ProductController 

Now write the some code of Product table at here 


<div class="row">
<div class="col-9">
<h2 class="text-success">Product List</h2>
</div>
<div class="col-3">
<a asp-action="Upsert" class="btn btn-info form-control">
New Product &nbsp; <i class="fas fa-plus"></i>
</a>
</div>
</div>
<div class="border p-2 m-2">
<table id="tblData" class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th>Author</th>
<th>ISBN</th>
<th>Price</th>
<th>Actions</th>
</tr>
</thead>
</table>
</div>

116) Now go to the ProductController and write the code of Index and JSON API for fetch the
data and sent to View, here we also write the Upsert and much more 

using Ecomm_Project2.DataAccess.Repository;
using Ecomm_Project2.DataAccess.Repository.IRepository;
using Microsoft.AspNetCore.Mvc;
using Microsoft.CodeAnalysis.Operations;

namespace Ecomm_Project2.Areas.Admin.Controllers
{
[Area("Admin")]
public class ProductController : Controller
{
private readonly IUnitOfWork _unitOfWork;
public ProductController(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}

public IActionResult Index()


{
return View();
}
#region APIs
[HttpGet]
public IActionResult GetAll()
{
return Json(new { data = _unitOfWork.Product.GetAll() });
}
#endregion
}
}

117) Now create a product.js file for View and write the code of show data at columns and
Sweet alert for delete button 

var dataTable;
$(document).ready(function () {
loadDataTable();
})
function loadDataTable() {
dataTable = $('#tblData').DataTable({
"ajax": { "url": "/Admin/Product/GetAll" },
"columns": [
{ "data": "title", "width": "15%" },
{ "data": "description", "width": "25%" },
{ "data": "author", "width": "15%" },
{ "data": "isbn", "width": "15%" },
{ "data": "price", "width": "15%" },
{
"data": "id",
"render": function (data) {
return `
<div class ="text-center">
<a href ="/Admin/Product/Upsert/${data}" class = "btn btn-info">
<i class ="fas fa-edit"></i>
</a>
<a class = "btn btn-danger" onclick =
Delete("/Admin/Product/Delete/${data}")>
<i class = "fas fa-trash-alt"></i>
</a>
</div>
`;
}
}
]
})

}
function Delete(url) {
swal({
text: "Delete Information !!",
title: "Want to delete data ?",
icon: "warning",
buttons: true,
dangerModel: true
}).then((willDelete) => {
if (willDelete) {
$.ajax({
url: url,
type: "DELETE",
success: function (data) {
if (data.success) {
toastr.success(data.message);
dataTable.ajax.reload();
}
else {
toastr.error(data.message);
}
}
})
}
})
}

118) Now register this js class at Index.cshtml of Product View 

119) Now add a new class in Ecomm_Project2.Models  add  class  ProductVM 

Write the List code at here of Product 

using Microsoft.AspNetCore.Mvc.Rendering;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.Models.ViewModels
{
public class ProductVM
{
public Product Product { get; set; }
public IEnumerable<SelectListItem> CategoryList { get; set; }
public IEnumerable<SelectListItem> CoverTypeList { get; set; }

}
}
120) Now go to the ProductController and Write the Upsert code at here 

121) Now add the view of Upsert 

Now make the Form in Upsert.cshtml of Product for take the input from the user 
@model Ecomm_Project2.Models.ViewModels.ProductVM
@{
ViewData["Title"] = "Upsert";
var title = Model.Product.Id != 0 ? "Edit Product" : "New Product";
}

<div class="row">
<h2 class="text-center text-primary border-bottom">@title</h2>
</div>
<div class="row">
<div class="col-md-6">
<form method="post" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
@if (Model.Product.Id != 0)
{
<input type="hidden" asp-for="@Model.Product.Id" />
}
<div class="form-group">
<label asp-for="Product.Title"></label>
<input asp-for="Product.Title" class="form-control" />
<span asp-validation-for="Product.Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Product.ISBN"></label>
<input asp-for="Product.ISBN" class="form-control" />
<span asp-validation-for="Product.ISBN" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Product.Description"></label>
<textarea asp-for="Product.Description" class="form-control"></textarea>
<span asp-validation-for="Product.Description" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Product.Author"></label>
<input asp-for="Product.Author" class="form-control" />
<span asp-validation-for="Product.Author" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Product.ListPrice"></label>
<input asp-for="Product.ListPrice" class="form-control" />
<span asp-validation-for="Product.ListPrice" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Product.Price"></label>
<input asp-for="Product.Price" class="form-control" />
<span asp-validation-for="Product.Price" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Product.Price50"></label>
<input asp-for="Product.Price50" class="form-control" />
<span asp-validation-for="Product.Price50" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Product.Price100"></label>
<input asp-for="Product.Price100" class="form-control" />
<span asp-validation-for="Product.Price100" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Product.CategoryId"></label>
@Html.DropDownListFor(m => Model.Product.CategoryId,Model.CategoryList,"Select Category",new
{@class = "form-control"})
<span asp-validation-for="Product.CategoryId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Product.CoverTypeId"></label>
@Html.DropDownListFor(m => Model.Product.CoverTypeId,Model.CoverTypeList,"Select CoverType",new
{@class = "form-control"})
<span asp-validation-for="Product.CoverTypeId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Product.ImageUrl"></label>
<input type="file" name="files" id="uploadBox" multiple class="form-control" />
</div>
<div class="form-group p-2 m-2">
@if (Model.Product.Id != 0)
{
<partial name="_EditAndBackToListButton" />
}
else
{
// <partial name="_CreateAndBackToListButton" />
<div class="row">
<div class="col">
<button type="submit" onclick="return ValData()"class="btn btn-info form-
control">Save</button>
</div>
<div class="col"><a asp-action="Index" class="btn btn-success form-control">Back To
List</a>
</div>
</div>
}
</div>

</form>
</div>
</div>
@section scripts{
<partial name="_ValidationScriptsPartial" />
<script
src="https://cdn.tiny.cloud/1/yceb7wqr2ps5v3vunieemb9syejgjl73j210uk6duakmo75e/tinymce/5/tinymce.min.js"
referrerpolicy="origin"></script>
<script>
tinymce.init({
selector: "textarea",
plugins: "lists",
menubar: "file edit format"
})
function ValData(){
if (document.getElementById("uploadBox").value == ""){
swal("Error","Please Select Image!!",'error');
return false;
}
}
</script>
}

122) Now add a new folder of name Images in wwwroot 


123) Now again add a new folder Products in Images folder 

124) Now go to the ProductController.cs and write the code for valid file path and valid
image number( more than one) 

using Ecomm_Project2.DataAccess.Repository;
using Ecomm_Project2.DataAccess.Repository.IRepository;
using Ecomm_Project2.Models;
using Ecomm_Project2.Models.ViewModels;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.CodeAnalysis.Operations;
using Microsoft.Data.SqlClient;
using System;
using System.Drawing.Printing;
using System.IO;
using System.Linq;

namespace Ecomm_Project2.Areas.Admin.Controllers
{
[Area("Admin")]
public class ProductController : Controller
{
private readonly IUnitOfWork _unitOfWork;
private readonly IWebHostEnvironment _webHostEnvironment;
public ProductController(IUnitOfWork unitOfWork, IWebHostEnvironment webHostEnvironment)
{
_unitOfWork = unitOfWork;
_webHostEnvironment = webHostEnvironment;
}

public IActionResult Index()


{
return View();
}
#region APIs
[HttpGet]
public IActionResult GetAll()
{
return Json(new { data = _unitOfWork.Product.GetAll() });
}
#endregion
public IActionResult Upsert(int? id)
{
ProductVM productVM = new ProductVM()
{
Product = new Product(),
CategoryList = _unitOfWork.Category.GetAll().Select(cl => new SelectListItem()
{
Text = cl.Name,
Value = cl.Id.ToString()
}),
CoverTypeList = _unitOfWork.CoverType.GetAll().Select(ct => new SelectListItem()
{
Text = ct.Name,
Value = ct.Id.ToString()
})
};
if (id == null) return View(productVM);
productVM.Product = _unitOfWork.Product.Get(id.GetValueOrDefault());
return View(productVM);
}
[HttpPost]
[AutoValidateAntiforgeryToken]
public IActionResult Upsert(ProductVM productVM)
{
if (ModelState.IsValid)
{
var webRootPath = _webHostEnvironment.WebRootPath;
var files = HttpContext.Request.Form.Files;
if (files.Count > 0)
{
var fileName = Guid.NewGuid().ToString();
var extension = Path.GetExtension(files[0].FileName);
var uploads = Path.Combine(webRootPath, @"Images\Products");
if(productVM.Product.Id != 0)
{
var imageExists = _unitOfWork.Product.Get(productVM.Product.Id).ImageUrl;
productVM.Product.ImageUrl = imageExists;
}
if(productVM.Product.ImageUrl != null)
{
var imagePath = Path.Combine(webRootPath,productVM.Product.ImageUrl.Trim('\\'));
if (System.IO.File.Exists(imagePath))
{
System.IO.File.Delete(imagePath);
}
}
using (var fileStream = new FileStream(Path.Combine(uploads, fileName + extension),
FileMode.Create))
{
files[0].CopyTo(fileStream);
}
productVM.Product.ImageUrl = @"\Images\Products\" + fileName + extension;
}
else
{
if(productVM.Product.Id != 0)
{
var imageExists = _unitOfWork.Product.Get(productVM.Product.Id).ImageUrl;
productVM.Product.ImageUrl = imageExists;
}
}
if (productVM.Product.Id == 0)
_unitOfWork.Product.Add(productVM.Product);
else
_unitOfWork.Product.Update(productVM.Product);
_unitOfWork.Save();
return RedirectToAction(nameof(Index));

}
else
{
productVM = new ProductVM()
{
Product = new Product(),
CategoryList = _unitOfWork.Category.GetAll().Select(cl => new SelectListItem()
{
Text = cl.Name,
Value = cl.Id.ToString()
}),
CoverTypeList = _unitOfWork.CoverType.GetAll().Select(ct => new SelectListItem()
{
Text= ct.Name,
Value = ct.Id.ToString()
})
};
if(productVM.Product.Id != 0)
{
productVM.Product = _unitOfWork.Product.Get(productVM.Product.Id);
}
}
return View(productVM);
}
}
}

125) Now go to the


Upsert.cshtml file of
Product and a space for the
Image 
126) Now write the code for delete details of Product in ProductController 
[HttpDelete]

public IActionResult Delete(int id)


{
var productInDb = _unitOfWork.Product.Get(id);
if (productInDb == null)
return Json(new { success = false, message = "Somthing went wrong!" });

//Delete File
var webRootPath = _webHostEnvironment.WebRootPath;
var imagePath = Path.Combine(webRootPath, productInDb.ImageUrl.Trim('\\'));
if (System.IO.File.Exists(imagePath))
{
System.IO.File.Delete(imagePath);
}
_unitOfWork.Product.Remove(productInDb);
_unitOfWork.Save();
return Json(new { success = true, message = "Data Deleted Successfully!" });
}

127) Now add few line of code in HomeController 

128) Now go to the HomeController and the write the code of card representation in Index 

@model IEnumerable<Ecomm_Project2.Models.Product>
<div class="row">
@foreach (var product in Model)
{
<div class="col-lg-3 col-md-6 ">
<div class="row p-2">
<div class="col-12p-1" style="border:1px solid #008cba; border-radius: 4px;">
<div class="card" style="border:4px;">
<img src="@product.ImageUrl" class="card-img-top rounded" />
<hr/>
<div class="pl-1">
<p class="card-title h5"><b style="color:#2c3e50">@product.Title</b></p>
<p class="card-title text-primary">by <b>@product.Author</b></p>
</div>
<div style="padding-left:5px;">
<p>List Price: <strike><b class="">[email protected]("0.00")</b></strike></p>
</div>
<div style="padding-left:5px;">
<p style="color:maroon">As low as: <b class="">[email protected]("0.00")</b></p>
</div>
</div>
<div>
<a asp-action="Details" class="btn btn-primary form-control border-0" asp-route-
id="@product.Id">Details</a>
</div>
</div>
</div>
</div>
}
</div>

129) Now add a new Company class in Ecomm_Project2.Models 


130) Now create the columns in the Company class 

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

namespace Ecomm_Project2.Models
{
public class Company
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Display(Name ="Street Address")]
public string StreetAddress { get; set; }
public string City { get; set; }
public string State { get; set; }
[Display(Name ="Postal Code")]
public string PostalCode { get; set; }
[Display(Name ="Phone Number")]
public string PhoneNumber { get; set; }
[Display(Name ="Is Authorized Company")]
public bool IsAuthorizedCompany { get; set; }
}
}

131) Now register/ add this class in ApplicationDbContext.cs 

132) Now add the migrations for set the tables in the database 

133) Now add a new Interface type class in Ecomm_Project2.DataAccess of folder IRepository
with name ICompanyRepository 

134) Now write the code of update tables in this interface class 

using Ecomm_Project2.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.DataAccess.Repository.IRepository
{
public interface ICompanyRepository:IRepository<Company>
{
void Update(Company company);
}
}
135) Now add a new class of name CompanyRepository in folder of Repository in
Ecomm_Project2.DataAccess 

136) Now write the code for connect this class with database in it

using Ecomm_Project2.DataAccess.Data;
using Ecomm_Project2.DataAccess.Repository.IRepository;
using Ecomm_Project2.Models;
using Microsoft.AspNetCore.Identity.UI.V4.Pages.Internal.Account;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.DataAccess.Repository
{
public class CompanyRepository : Repository<Company>, ICompanyRepository
{
private readonly ApplicationDbContext _context;
public CompanyRepository(ApplicationDbContext context) : base(context)
{
_context = context;
}

public void Update(Company company)


{
_context.Update(company);
}
}
}

137) Now go to the IUnitOfWork add this class in it 

138) Now add this Company class in UnitOfWork 

139) Now add the MVC Controller in Areas  Admin  Controllers of name CompanyController

140) Now write the code at here and add the UnitOfWork 

using Ecomm_Project2.DataAccess.Repository.IRepository;
using Microsoft.AspNetCore.Mvc;

namespace Ecomm_Project2.Areas.Admin.Controllers
{
[Area("Admin")]
public class CompanyController : Controller
{
private readonly IUnitOfWork _unitOfWork;
public CompanyController(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}

public IActionResult Index()


{
return View();
}
}
}
141) Now add this Company at navbar in _Layput.cshtml through li item 

<li class="nav-item dropdown">


<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Company/User
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" asp-area="Admin" asp-controller="Company" asp-
action="Index">Company</a>
</div>
</li>

142) Now add the Index page of Company class and write the following code

<div class="row">
<div class="col-9">
<h2 class="text-success">Company List</h2>
</div>
<div class="col-3">
<a asp-action="Upsert" class="btn btn-info form-control">
Add New Company &nbsp; <i class="fas fa-plus"></i>
</a>
</div>
</div>
<div class="border p-2 m-2">
<table id="tblData" class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>Name</th>
<th>Address</th>
<th>City</th>
<th>State</th>
<th>Phone Number</th>
<th>Is Authorized</th>
<th>Action</th>
</tr>
</thead>
</table>
</div>
@section scripts {
<script src="~/js/company.js"></script>
}

143) Now for access these columns data we add a GetAll() name API in CompanyController 

144) Now add a company.js file in js folder 

var dataTable;
$(document).ready(function () {
loadDataTable();
})
function loadDataTable() {
dataTable = $('#tblData').DataTable({
"ajax": { "url": "/Admin/Company/GetAll" },
"columns": [
{ "data": "name", "width": "15%" },
{ "data": "streetAddress", "width": "15%" },
{ "data": "city", "width": "15%" },
{ "data": "state", "width": "15%" },
{ "data": "phoneNumber", "width": "15%" },
{
"data": "isAuthorizedCompany",
"render": function (data) {
if (data) {
return `<input type="checkbox" checked disable />`;
}else
{
return `<input type="checkbox" disable />`;
}
}

},
{
"data": "id",
"render": function (data) {
return `
<div class ="text-center">
<a href ="/Admin/Company/Upsert/${data}" class = "btn btn-info">
<i class ="fas fa-edit"></i>
</a>
<a class = "btn btn-danger" onclick = Delete("/Admin/Company/Delete/${data}")>
<i class = "fas fa-trash-alt"></i>
</a>
</div>
`;
}
}
]
})

function Delete(url) {
swal({
text: "Delete Information !!",
title: "Want to delete data ?",
icon: "warning",
buttons: true,
dangerModel: true
}).then((willDelete) => {
if (willDelete) {
$.ajax({
url: url,
type: "DELETE",
success: function (data) {
if (data.success) {
toastr.success(data.message);
dataTable.ajax.reload();
}
else {
toastr.error(data.message);
}
}
})
}
})
}

145) Now go to the CompanyController and write the code of Upsert/Add and Update code 

146) Now add the Razor View of Upsert action of Company and create the input field 

@model Ecomm_Project2.Models.Company
@{
ViewData["Title"] = "Upsert";
var title = Model.Id != 0 ? "Edit Company" : "New Company";
}
<form method="post">
<div class="row border">
<div class="col-12">
<h2 class="text-success border-bottom">@title</h2>
</div>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="col-8 border rounded p-2 m-2">
<div class="form-group row p-2 m-2">
<div class="col-4">
<label asp-for="Name"></label>
</div>
<div class="col-8">
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
</div>

<div class="form-group row p-2 m-2">


<div class="col-4">
<label asp-for="StreetAddress"></label>
</div>
<div class="col-8">
<input asp-for="StreetAddress" class="form-control" />
<span asp-validation-for="StreetAddress" class="text-danger"></span>
</div>
</div>

<div class="form-group row p-2 m-2">


<div class="col-4">
<label asp-for="State"></label>
</div>
<div class="col-8">
<input asp-for="State" class="form-control" />
<span asp-validation-for="State" class="text-danger"></span>
</div>
</div>

<div class="form-group row p-2 m-2">


<div class="col-4">
<label asp-for="City"></label>
</div>
<div class="col-8">
<input asp-for="City" class="form-control" />
<span asp-validation-for="City" class="text-danger"></span>
</div>
</div>

<div class="form-group row p-2 m-2">


<div class="col-4">
<label asp-for="PostalCode"></label>
</div>
<div class="col-8">
<input asp-for="PostalCode" class="form-control" />
<span asp-validation-for="PostalCode" class="text-danger"></span>
</div>
</div>

<div class="form-group row p-2 m-2">


<div class="col-4">
<label asp-for="PhoneNumber"></label>
</div>
<div class="col-8">
<input asp-for="PhoneNumber" class="form-control" />
<span asp-validation-for="PhoneNumber" class="text-danger"></span>
</div>
</div>

<div class="form-group row p-2 m-2">


<div class="col-4">
<label asp-for="IsAuthorizedCompany"></label>
</div>
<div class="col-8">
<input type="checkbox" asp-for="IsAuthorizedCompany" />
<span asp-validation-for="IsAuthorizedCompany" class="text-danger"></span>
</div>
</div>
<div class="form-group row p-2 m-2">
<div class="col-8 offset-4">
@if (Model.Id == 0)
{
<partial name="_CreateAndBackToListButton" />
}
else
{
<partial name="_EditAndBackToListButton" />
}

</div>
</div>
</div>
</div>

</form>

@section scripts{
<partial name="_ValidationScriptsPartial" />
}
147) Now write the Delete API code in CompanyController 

148) Now for use the Identity framework, go to the main project, Ecomm_Project2  right
click  add  New Scaffolded item  Identity  add  choose Override all file checkbok
button  in below option Data context class  choose, DataAccess.Data  add 
149) Now go to Ecomm_Project2.Models, right click  add new class  name ApplicationUser

Now create the models of this class 


using Microsoft.AspNetCore.Identity;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.Models
{
public class ApplicationUser : IdentityUser
{
[Required]
public string Name { get; set; }
[Display(Name ="Street Address")]
public string StreetAddress { get; set; }
public string City { get; set; }
public string State { get; set; }
[Display(Name ="Postal Code")]
public string PostalCode { get; set; }
[Display(Name ="Company")]
public int? CompanyId { get; set; }
[ForeignKey("CompanyId")]
public Company Company { get; set; }
[NotMapped]
public string Role { get; set; }
}
}
150) Now add this class in ApplicationDbContext file 

151) Now add the Migration, and update the database 

152) Now add an Interface type class in IRepository folder of name


IApplicationUserRepository 

using Ecomm_Project2.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.DataAccess.Repository.IRepository
{
public interface IApplicationUserRepository : IRepository<ApplicationUser>
{
}
}
153) Now add a new class in Repository folder of name ApplicationUserRepository 
using Ecomm_Project2.DataAccess.Data;
using Ecomm_Project2.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.DataAccess.Repository.IRepository
{
public class ApplicationUserRepository : Repository<ApplicationUser>, IApplicationUserRepository
{
private readonly ApplicationDbContext _context;
public ApplicationUserRepository(ApplicationDbContext context) : base(context)
{
_context = context;
}
}
}

154) Now add the IApplicationUserRepository in the IUnitOfWork 

155) Again, add the IApplicationUserRepository in UnitOfWork file 

156) Now go to the Register.cshtml.cs file and add the some new custom columns 

[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.",
MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
// Add custom columns
[Required]
public string Name { get; set; }
[Display(Name ="Street Address")]
public string StreetAddress { get; set; }
public string City { get; set; }
public string State { get; set; }
[Display(Name ="Postal Code")]
public string PostalCode { get; set; }
[Display(Name ="Phone Number")]
public string PhoneNumber { get; set; }
public int? CompanyId { get; set; }
public string Role { get; set; }
}
157) Now go to the Register.cshtml file and add these new custom columns in html file 

<div class="row">
<div class="col-md-4">
<form asp-route-returnUrl="@Model.ReturnUrl" method="post">
<h4>Create a new account.</h4>
<hr />
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.Name"></label>
<input asp-for="Input.Name" class="form-control" />
<span asp-validation-for="Input.Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.StreetAddress"></label>
<input asp-for="Input.StreetAddress" class="form-control" />
<span asp-validation-for="Input.StreetAddress" class="text-
danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.PhoneNumber"></label>
<input asp-for="Input.PhoneNumber" class="form-control" />
<span asp-validation-for="Input.PhoneNumber" class="text-
danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.State"></label>
<input asp-for="Input.State" class="form-control" />
<span asp-validation-for="Input.State" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.City"></label>
<input asp-for="Input.City" class="form-control" />
<span asp-validation-for="Input.City" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.PostalCode"></label>
<input asp-for="Input.PostalCode" class="form-control" />
<span asp-validation-for="Input.PostalCode" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.Email"></label>
<input asp-for="Input.Email" class="form-control" />
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.Password"></label>
<input asp-for="Input.Password" class="form-control" />
<span asp-validation-for="Input.Password" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.ConfirmPassword"></label>
<input asp-for="Input.ConfirmPassword" class="form-control" />
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Register</button>
</form>
</div>
<div class="col-md-6 col-md-offset-2">
<section>
<h4>Use another service to register.</h4>
<hr />
@{
if ((Model.ExternalLogins?.Count ?? 0) == 0)
{
<div>
<p>
There are no external authentication services configured. See <a
href="https://go.microsoft.com/fwlink/?LinkID=532715">this article</a>
for details on setting up this ASP.NET application to support logging in via
external services.
</p>
</div>
}
else
{
<form id="external-account" asp-page="./ExternalLogin" asp-route-
returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
<div>
<p>
@foreach (var provider in Model.ExternalLogins)
{
<button type="submit" class="btn btn-primary" name="provider"
value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
}
</p>
</div>
</form>
}
}
</section>
</div>
</div>

158) Now add the Identity of User and Role and also add the Razors pages in Startup.cs
file 

159) We add the Identity Framework in the Models project, because we are using the
Identity framework 

160) Now go to the Ecomm_Project2.Utility folder and add a new class EmailSender 

using Microsoft.AspNetCore.Identity.UI.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Ecomm_Project2.Utility
{
public class EmailSender : IEmailSender
{
public Task SendEmailAsync(string email, string subject, string htmlMessage)
{
throw new NotImplementedException();
}
}
}

161) Now register this email class in the Startup.cs file 

162) Now assign the variables of ApplicationUser.cs(in Models Project) class in


Register.cshtnl.cs 

163) Now comments these line of code 

164) Now assign the role of user in the SD.cs class in Utility project 

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

namespace Ecomm_Project2.Utility
{
public static class SD
{
// cover type store procedure
public const string Proc_GetCoverTypes = "GetCoverTypes";
public const string Proc_GetCoverType = "GetCoverType";
public const string Proc_CreateCoverType = "CreateCoverType";
public const string Proc_UpdateCoverType = "UpdateCoverType";
public const string Proc_DeleteCoverType = "DeleteCoverType";

//Roles
public const string Role_Admin = "Admin";
public const string Role_Employee = "Employee User";
public const string Role_Company = "Company User";
public const string Role_Individual = "Individual User";
}
}

165) Now add/ register the Role in Register.cshtml.cs file 

166) Now assign the Role to Admin 

167) When the Admin is created the comment this line, because the first admin user is
created 
168) Add the Role and Company in InputModel 

169) Add the IUnitOfWork in the RegisterModel class of Register.cshtml.cs file 

170) Now assign the CompanyList data in the InputModel class 

171) Now assign the role to all the user instead of the Individual user in
Registr.cshtml.cs file 
172) Now create the dropdown list for the select the Role of Admin and the Company Id for
the Admin in Register.cshtml
Firstly, add this 

<div class="form-group">
<label asp-for="Input.ConfirmPassword"></label>
<input asp-for="Input.ConfirmPassword" class="form-control" />
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
</div>

@if (User.IsInRole(SD.Role_Admin))
{

<div class="form-group">
<label asp-for="Input.CompanyId"></label>
@Html.DropDownListFor(m => m.Input.CompanyId, Model.Input.CompanyList,"Select Role",new{@class
=" form-control"})
<span asp-validation-for="Input.CompanyId" class="text-danger"></span>
</div>

<div class="form-group">
<label asp-for="Input.Role"></label>
@Html.DropDownListFor(m => m.Input.Role, Model.Input.RoleList,"Select Role",new{@class ="
form-control"})
<span asp-validation-for="Input.Role" class="text-danger"></span>
</div>

}
<button type="submit" class="btn btn-primary">Register</button>
</form>

173) Now create a new User controller in the Areas  Admin Controllers  Right
Click 
174) Now add all the user in the list and give the access to the Admin user to delete the
other user 

using Ecomm_Project2.DataAccess.Data;
using Ecomm_Project2.Utility;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Linq;

namespace Ecomm_Project2.Areas.Admin.Controllers
{
[Area("Admin")]
public class UserController : Controller
{
private readonly ApplicationDbContext _context;
public UserController(ApplicationDbContext context)
{
_context = context;

}
public IActionResult Index()
{
return View();
}
#region APIs
[HttpGet]
public IActionResult GetAll()
{
var userList = _context.ApplicationUsers.Include(a => a.Company).ToList(); // AspNetUsers
var roles = _context.Roles.ToList(); // AspNetRoles
var userRoles = _context.UserRoles.ToList(); // AspNetUserRoles

foreach (var user in userList)


{
var roleId = userRoles.FirstOrDefault(r => r.UserId == user.Id).RoleId;
user.Role = roles.FirstOrDefault(r => r.Id == roleId).Name;
if (user.Company == null)
{
user.Company = new Models.Company()
{
Name = ""
};
}
}
var adminUser = userList.FirstOrDefault(u => u.Role == SD.Role_Admin);
userList.Remove(adminUser);
return Json(new {data = userList});

}
#endregion
}
}

175) Now add the Razor View of Index action of User controller 

Now create the table for show the data of user 

<div class="row">
<div class="col-9">
<h2 class="tet-primary">User List</h2>
</div>
<div class="col-3">
<a asp-area="Identity" class="btn btn-info" asp-page="/Account/Register">
<i class="fas fa-plus">&nbsp;Create New User</i>
</a>
</div>
</div>
<div class="border rounded p-2 m-2">
<table id="tblData" class="table table-borderless table-striped">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Phone Number</th>
<th>Company</th>
<th>Role</th>
<th>Actions</th>
</tr>
</thead>
</table>
</div>

176) Now add this user in the navbar at the _Layout.cs file 

177) Now add a user.js file to show the data in the columns from the database 

var dataTable;
$(document).ready(function () {
loadDataTable();
})
function loadDataTable() {

dataTable = $('#tblData').DataTable({
"ajax": {
"url": "/Admin/User/GetAll"
},
"columns": [
{ "data": "name", "width": "15%" },
{ "data": "email", "width": "15%" },
{ "data": "phoneNumber", "width": "15%" },
{ "data": "company.name", "width": "15%" },
{ "data": "role", "width": "15%" },
{
"data": {
id: "id", lockoutEnd: "lockoutEnd"
},
"render": function (data) {
var today = new Date().getTime();
var lockOut = new Date(data.lockoutEnd).getTime();
if (lockOut > today) {

//User Locked
return `
<div class="text-center">
<a class="btn btn-danger" onclick=LockUnLock('${data.id}')>UnLock</a>
</div>
`;
}
else {
// user unlock
return `
<div class="text-center">
<a class="btn btn-success" onclick=LockUnLock('${data.id}')>Lock</a>
</div>
`;
}
}

} ] })}

function LockUnLock(id) {
$.ajax({
url: "/Admin/User/LockUnlock",
type: "POST",
data: JSON.stringify(id),
contentType: "application/json",
success: function (data) {
if (data.success) {
toastr.success(data.message);
dataTable.ajax.reload();
}
else {
toastr.error(data.message);
}
} })}

178) Now add this user.js file in Index.cshtml of UserController.cs file 

179) Now write the code of OnSubmit data of LockUnlock code in UserController.cs 

180) Now add the role of the user in Register.cshtml.cs 


181) Now, after these steps when you run this project, you might be got exception, this is
because of some data/records are already be store during the fill the columns. So to remove
this type of exceptions firstly delete the data from the database of the
AspNetUser,AspNetUserRole table.
After, this we can resolve the error.

182) Now write the code in Register.cshtml.cs for navigate the user according to its role

183) Now Authorized the Page to the user according to their role, add the Authorize word
below the Admin in Category, CoverType, Product, Company and User files 

184) Now, when those pages are not access by the user and he/she get those error, we
change this code. For this goto the startup.cs page and some pages path 
185) Now to hide the Navbar options from the user there should be some changes in the
_Layout.cs file like this 

@if (User.IsInRole(SD.Role_Admin))
{
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-
toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Select
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" asp-area="Admin" asp-controller="Category" asp-action="Index">Category</a>
<a class="dropdown-item" asp-area="Admin" asp-controller="CoverType" asp-action="Index">Cover
Type</a>
<a class="dropdown-item" asp-area="Admin" asp-controller="Product" asp-action="Index">Product</a>

</div>
</li>
}
@if (User.IsInRole(SD.Role_Admin) || User.IsInRole(SD.Role_Employee))
{
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-
toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Company/User
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" asp-area="Admin" asp-controller="Company" asp-action="Index">Company</a>
<hr />
<a class="dropdown-item" asp-area="Admin" asp-controller="User" asp-action="Index">Users</a>
</div>
</li>
}

186) Now for the Open Authentication like, the user can login with the Facebook, Google
account etc. so for this we must be install their packages. 
187) Now to add these authentications go to the startup.cs file 

Note! These ids are only for sample no the real. When you no have google ClientId and ClientSecret
then firstly make sure it comment otherwise it show the error, because you don’t have these id.

188) Now go to the ExternalLogin.cshtml.cs and do some changes for add new input field,
when the user login through the Facebook etc. 
189) Now write this code in ExternalLogin.cshtml.cs for new Input field 

190) Now create the Input field in ExternalLogin.cshtml 

@page
@model ExternalLoginModel
@{
ViewData["Title"] = "Register";
}

<h1>@ViewData["Title"]</h1>
<h4 id="external-login-title">Associate your @Model.ProviderDisplayName account.</h4>
<hr />

<p id="external-login-description" class="text-info">


You've successfully authenticated with <strong>@Model.ProviderDisplayName</strong>.
Please enter an email address for this site below and click the Register button to finish
logging in.
</p>

<div class="row">
<div class="col-md-4">
<form asp-page-handler="Confirmation" asp-route-returnUrl="@Model.ReturnUrl" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.Name"></label>
<input asp-for="Input.Name" class="form-control" />
<span asp-validation-for="Input.Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.Email"></label>
<input asp-for="Input.Email" class="form-control" />
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.StreetAddress"></label>
<input asp-for="Input.StreetAddress" class="form-control" />
<span asp-validation-for="Input.StreetAddress" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.State"></label>
<input asp-for="Input.State" class="form-control" />
<span asp-validation-for="Input.State" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.City"></label>
<input asp-for="Input.State" class="form-control" />
<span asp-validation-for="Input.State" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.PostalCode"></label>
<input asp-for="Input.PostalCode" class="form-control" />
<span asp-validation-for="Input.PostalCode" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.PhoneNumber"></label>
<input asp-for="Input.PhoneNumber" class="form-control" />
<span asp-validation-for="Input.PhoneNumber" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Register</button>
</form>
</div>
</div>

@section Scripts {
<partial name="_ValidationScriptsPartial" />
}

191) If we want to access or retrieve the data from Facebook other than email and name,
like Address, city, phone number etc then we can’t receive the data.

That’s why now this line make comment, because the Facebook don’t send this data of the
user.

192) Now this type of data take from the user manually. For this we create the multiple
input types in ExternalLogin.cshtml.cs 

193) Now we can write the code for authentication via google. So firstly we create a
account on the google. Go the console.developers.google website 
a) Now click on NEW PROJECT at top right side
b) Now write the Project name in the input field and create 

c) Now click on SELECT PROJECT in pop-up window show 


d) Now select ENABLE APIS AND SERVICES 

e) If we can’t find the Goople+ API then manually search and choose it 

f) Now click on ENABLE 

g) Now go to the OAuth consent screen at left sidebar 

h) Now choose the External option and then CREATE 


i) Now fill some details like the, App name and the User support email and Developer
contact information 

j) Now click on Credential option at the left sidebar 

k) Now click on the CREATE THE CTEDENTIALS link 

l) Now choose the OAuth client Id option 


m) Now choose the Application type as Web application 

n) Now paste the local url of the project which is show at the browser in the URls 1 input
field and also write the Authorized redirect URls link and click on CREATE button 

o) Now the OAuth Client is created and there are 2 values are generated like, Your Client
ID and Your Client Secret. Copy these two Ids and paste it in the Startup.cs file as 
p) Now when we add this, there is create a another button Google like Facebook button in
the Login page 

q) When we click on the login with Google button, then we go on the Google Authentication
page like 

r) Now choose your account and login with it and after successfully login we can see the
same name of user in the Navbar by which we login.

194) There we can also add some other Authentication type. It means if there are add
restriction on user to access the web page like, Home, Privacy or other then we can add the
[AllowAnonymous] at the above on the Action name in CategoryController.cs like 

But now we are not adding this functionality, so now we remove these.

195) Now create a new class ShoppingCart.cs in Ecomm_Project2.Models 


Add these models in this class 
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.Models
{
public class ShoppingCart
{
public ShoppingCart()
{
Count = 1;
}
public int Id { get; set; }
public string ApplicationUserId { get; set; }
[ForeignKey("ApplicationUserId")]
public ApplicationUser ApplicationUser { get; set; }
public int ProductId { get; set; }
[ForeignKey("ProductId")]
public Product Product { get; set; }
public int Count { get; set; }
[NotMapped]
public double Price { get; set; }
}
}

196) Now register this class in ApplicationDbContext.cs 

197) Now add the migration and Update database 


198) Now add a new interface class IShoppingCartRepository in IRepository folder 

using Ecomm_Project2.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.DataAccess.Repository.IRepository
{
public interface IShoppingCartRepository : IRepository<ShoppingCart>
{
void Update(ShoppingCart shoppingCart);
}
}
199) Now add a new class ShoppingCartRepository.cs in Repository folder 
using Ecomm_Project2.DataAccess.Data;
using Ecomm_Project2.DataAccess.Repository.IRepository;
using Ecomm_Project2.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.DataAccess.Repository
{
public class ShoppingCartRepository : Repository<ShoppingCart>, IShoppingCartRepository
{
private readonly ApplicationDbContext _context;
public ShoppingCartRepository(ApplicationDbContext context) : base(context)
{
_context = context;
}

public void Update(ShoppingCart shoppingCart)


{
_context.ShoppingCarts.Update(shoppingCart);
}
}
}

200) Now add this IShoppingCartRepository in IUnitOfWork 

201) Now add this IShoppingCartRepository in UnitOfWork 

202) Now to show the details of the item, we create the Detail action in HomeController.cs
file 
203) Now add the Razor view of this Details action 

@model Ecomm_Project2.Models.ShoppingCart
<form method="post">

<input type="hidden" asp-for="@Model.ProductId" />


<div class="container background-White">
<div class="card">
<div class="card-header bg-light text-light ml-0 row container">
<div class="col-12 col-md-6">
<h2 class="text-primary">@Model.Product.Title</h2>
<p class="text-warning">@Model.Product.Author</p>
</div>
<div class="col-12 col-md-6 text-md-right pt-4">
<span class="badge badge-success pt-2" style="height:30px;font-
weight:bold;">@Model.Product.CoverType.Name</span>
<span class="badge badge-warning pt-2" style="height:30px;font-
weight:bold;">@Model.Product.Category.Name</span>
</div>
</div>
<div class="card-body">
<div class="container rounded p-2">
<div class="row">
<div class="col-8 col-lg-8">

<div class="row pl-2">


<h6 class="text-muted">ISBN : @Model.Product.ISBN</h6>
</div>
<div class="row pl-2">
<h6 class="text-muted pb-2">List Price: <strike>$
@Model.Product.ListPrice</strike></h6>
</div>
<div class="row text-center pl-2" style="font-weight:bold">
<div class="p-1 col-2 border-bottom" style="background-color:#d5eaff;">
<div>Quantity</div>
</div>
<div class="p-1 col-2 border-bottom" style="background-color:#d5eaff;">
<div>1-49</div>
</div>
<div class="p-1 col-2 border-bottom" style="background-color:#d5eaff;">
<div>50-99</div>
</div>
<div class="p-1 col-2 border-bottom" style="background-color:#d5eaff;">
<div>100+</div>
</div>
</div>

<div class="row text-center pl-2" style="color:maroon; font-weight:bold">


<div class="p-1 col-2" style="background-color:#d5eaff;">
<div>Price</div>
</div>
<div class="p-1 col-2" style="background-color:#d5eaff;">
<div>@Model.Product.Price</div>
</div>
<div class="p-1 col-2" style="background-color:#d5eaff;">
<div>@Model.Product.Price50</div>
</div>
<div class="p-1 col-2" style="background-color:#d5eaff;">
<div>@Model.Product.Price100</div>
</div>
</div>

<div class="row pl-2">


<p class="text-secondary">@Html.Raw(@Model.Product.Description)</p>
</div>
<div class="row pl-2 m-md-5">
<div class="col-3 text-primary"><h4>Count</h4></div>
<div class="col-8"><input class="form-control" asp-for="@Model.Count" /></div>
</div>
</div>
<div class="col-12 col-lg-3 offset-lg-1 text-center">
<img src="@Model.Product.ImageUrl" width="100%" class="rounded" />
</div>
</div>
</div>
</div>
<div class="card-footer">
<div class="row">
<div class="col-12 col-md-3 pb-1 offset-lg-3 offset-md-0">
<a class="btn btn-success form-control btn-square btn-md" asp-action="Index"
style="height:40px;font-weight:bold;">Back to List</a>
</div>
<div class="col-12 col-md-3 pb-1">

<button type="submit" value="Add to Cart" class="btn btn-primary btn-square btn-md


form-control" style="height:40px;font-weight:bold;">Add to Cart</button>

</div>
</div>
</div>
</div>
</div>
</form>
204) Now write the code for add to cart data/item in ShoppingCart at HomeController 

[HttpPost]
[AutoValidateAntiforgeryToken]
[Authorize]
public IActionResult Details(ShoppingCart shoppingCart)
{
shoppingCart.Id = 0;
if (ModelState.IsValid)
{
var claimsIdentity = (ClaimsIdentity)User.Identity;
var claim = claimsIdentity.FindFirst(ClaimTypes.NameIdentifier);
shoppingCart.ApplicationUserId = claim.Value;

var shoppingCartFromDb = _unitOfWork.ShoppingCart.FirstOrDefault


(sp => sp.ApplicationUserId == claim.Value &&
sp.ProductId == shoppingCart.ProductId);
if(shoppingCartFromDb == null)
{
//Add
_unitOfWork.ShoppingCart.Add(shoppingCart);
}
else
{
//Update
shoppingCartFromDb.Count += shoppingCart.Count;
}
_unitOfWork.Save();
return RedirectToAction(nameof(Index));
}
else
{
var productInDb = _unitOfWork.Product.FirstOrDefault
(p => p.Id == shoppingCart.ProductId, includeProperties: "Category,CoverType");
if (productInDb == null) return NotFound();
var shoppingCartEdit = new ShoppingCart()
{
Product = productInDb,
ProductId = productInDb.Id
};
return View(shoppingCartEdit);
}
}

Add this line in Details.cshtml

205) Now create the session cookies in Startup.cs file 


206) Now add the session in the HomeController.cs Index method to show the Cart Item number

207) Now add/ register the session variable in the SD.cs file as a stored variable 

Add this variable in HomeController.cs  Index method, like 

208) Now add the Icon in navbar to show the Cart Item number details, in _Layout.cshtml 

Firstly, add these lines in starting 


209) Now add the session variable in logout page, because when the user logout then the cart
item auto be become 0 because without the user there is no any cart item in the list 
So go to the Logout.cshtml.cs and the session variable in the OnPost method 

210) Now add a new controller CartControllerin in Customer  Controller 

Now write the code in it 


using Ecomm_Project2.DataAccess.Repository.IRepository;
using Microsoft.AspNetCore.Mvc;
using Microsoft.CodeAnalysis.Operations;
using System.Net.Sockets;

namespace Ecomm_Project2.Areas.Customer.Controllers
{
[Area("Customer")]
public class CartController : Controller
{
private readonly IUnitOfWork _unitOfWork;
public CartController(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}

public IActionResult Index()


{
return View();
}
}
}

211) Now add the View of Index action in CartController.cs 

<form method="post">
<br />
<div class="backgroundWhiteBorder">
<div class="container">
<div class="card">
<div class="card-header bg-dark text-light ml-0 row container">
<div class="col-6">
<i class="fa fa-shopping-cart"></i> &nbsp;
Shopping Cart
</div>
<div class="col-6 text-right">
<a asp-controller="Home" asp-action="Index" class="btn btn-outline-info btn-sm">Continue
Shopping</a>
</div>
</div>
<div class="card-body">
<div class="row">
<div class="d-none d-lg-block col-lg-1 text-center py-2">
<img src="https://via.placeholder.com/150" class="rounded" width="100%" />
</div>
<div class="col-12 text-sm-center col-lg-6 text-lg-left">
<h5><strong>--TITLE--</strong></h5>
<p><small>--DESCRIPTION--</small></p>
</div>
<div class="col-12 text-sm-center col-lg-5 text-lg-right row">
<div class="col-4 text-md-right" style="padding-top:5px;">
<h6><strong>--Price --<span class="text-muted">x</span> --Count-- </strong></h6>
</div>
<div class="col-6 col-sm-4 col-lg-6">
<div class="float-right mx-1">
<button type="submit" class="btn btn-primary">
<i class="fas fa-plus"></i>
</button>
</div>
<div class="float-right mx-1">
<button type="submit" class="btn btn-danger">
<i class="fas fa-minus"></i>
</button>
</div>
</div>
<div class="col-2 col-sm-4 col-lg-2 text-right">
<button type="submit" class="btn btn-outline-danger">
<i class="fas fa-trash"></i>
</button>
</div>
</div>
</div>
<hr />

<div class="row">
<div class="col-12 col-md-6 offset-md-6 col-lg-4 offset-lg-8 pr-4">
<ul class="list-group">
<li class="list-group-item d-flex justify-content-between bg-light">
<span class="text-info"> Total (USD)</span>
<strong class="text-info">$ <span id="txtOrderTotal">--TOTAL--</span></strong>
</li>
</ul>
</div>
</div>
</div>
<div class="card-footer">
<div class="card-footer row">

<div class="col-sm-12 col-lg-4 col-md-6 offset-lg-8 offset-md-6 ">

<a class="btn btn-success form-control">Summary</a>


</div>
</div>
</div>
</div>
</div>
</div>
</form>

212) Now create a public type OrderHeader Model class in Ecomm_Project2.Models 

Now add the columns name 

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.Models
{
public class OrderHeader
{
public int Id { get; set; }
public string ApplicationUserId { get; set; }
[ForeignKey("ApplicationUserId")]
public ApplicationUser ApplicationUser { get; set; }
[Required]
public DateTime OrderDate { get; set; }
[Required]
public DateTime ShippingDate { get; set; }
[Required]
public double OrderTotal { get; set; }

public string TrackingNumber { get; set; }

public string Carrier { get; set; }


public string OrderStatus { get; set; }
public string PaymentStatus { get; set; }
public DateTime PaymentDate { get; set; }
public DateTime PaymentDueDate { get; set; }
public string TransactionId { get; set; }
[Required]
public string Name { get; set; }
[Required]
[Display(Name = "Street Address")]
public string StreetAddress { get; set; }
[Required]
public string City { get; set; }
[Required]
public string State { get; set; }
[Required]
[Display(Name = "Postal Code")]
public string PostalCode { get; set; }
[Required]
[Display(Name ="Phone Number")]
public string PhoneNumber { get; set; }
}
}

213) Now again add a new public type class OrderDetails in Ecomm_Project2.Models 

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;

namespace Ecomm_Project2.Models
{
public class OrderDetails
{
public int Id { get; set; }
public int OrderHeaderId { get; set; }
[ForeignKey("OrderHeaderId")]
public OrderHeader OrderHeader { get; set; }
public int ProductId { get; set; }
[ForeignKey("ProductId")]
public Product Product { get; set; }
public int Count { get; set; }
public double Price { get; set; }

}
}
214) Now add these two class in ApplicationDbContetxt 

215) Now add the migration and update database 

216) Now make the interface of OrderHeader and OrderDetais one by one.
First we create the pubic Interface type class of OrderHeader of with the name
IOrderHeaderRepository.cs 
using Ecomm_Project2.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.DataAccess.Repository.IRepository
{
public interface IOrderHeaderRepository : IRepository<OrderHeader>
{
void Update(OrderHeader orderHeader);
}
}

217) Now add a public class of this OrderHeader class in Repository folder 

using Ecomm_Project2.DataAccess.Data;
using Ecomm_Project2.DataAccess.Repository.IRepository;
using Ecomm_Project2.Models;
using Microsoft.AspNetCore.Identity.UI.V4.Pages.Internal.Account.Manage;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.DataAccess.Repository
{
public class OrderHeaderRepository :
Repository<OrderHeader>,IOrderHeaderRepository
{
private readonly ApplicationDbContext _context;
public OrderHeaderRepository(ApplicationDbContext
context) : base(context)
{
_context = context;
}

public void Update(OrderHeader orderHeader)


{
_context.OrderHeaders.Update(orderHeader);
}
}
}

218) Now add this IOrderHeaderRepository in IUnitOfWork 

219) Also add this IOrderOfRepository in UnitOfWork 


220) Now make the public type interface class IOrderDetailsRepository in IRepository folder

using Ecomm_Project2.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.DataAccess.Repository.IRepository
{
public interface IOrderDetailsRepository :
IRepository<OrderDetails>
{
void Update(OrderDetails orderDetails);

}
}

221) Now make its public type OrderDetailsRepository in Repository folder 

using Ecomm_Project2.DataAccess.Data;
using Ecomm_Project2.DataAccess.Repository.IRepository;
using Ecomm_Project2.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.DataAccess.Repository
{
public class OrderDetailsRepository :
Repository<OrderDetails>, IOrderDetailsRepository
{
private readonly ApplicationDbContext _context;
public
OrderDetailsRepository(ApplicationDbContext context) :
base(context)
{
_context = context;
}

public void Update(OrderDetails orderDetails)


{
_context.OrderDetails.Update(orderDetails);
}
}
}

222) Now add this class in IUnitOfWork.cs 

223) Now add this class in UnitOfWork.cs 


224) Now add these classes as a store procedure and generate the formula for auto calculate
the price of item according to their quantity and also create the logic for auto remove the
HTML element in the Description box in SD.cs class 

// order status
public const string OrderStatusPending = "Pending";
public const string OrderStatusApproved = "Approved";
public const string OrderStatusInProgress = "Processing";
public const string OrderStatusShipped = "Shipped";
public const string OrderStatusCancelled = "Cancelled";
public const string OrderStatusRefunded = "Refunded";

//Payment status
public const string PaymentStatusPending = "Pending";
public const string PaymentStatusApproved = "Approved";
public const string PaymentStatusDelayPayment = "PaymentStatusDelay";
public const string PaymentStatusRejected = "Rejected";

public static double GetPriceBasedOnQuantity(double quantity, double price, double price50, double
price100)
{
if (quantity < 50)
return price;
else if (quantity < 100)
return price50;
else
return price100;
}
// <p>hello</p>
public static string ConvertToRawHtml(string source)
{
char[] array = new char[source.Length];
int arrayIndex = 0;
bool inside = false;
for(int i = 0; i < source.Length; i++)
{
char let = source[i]; // <p>
if(let == '<')
{
inside = true;
continue;
}
if(let == '>')
{
inside = false;
continue;
}
if (!inside)
{
array[arrayIndex] = let; // hello
arrayIndex++;
}
}
return new string( array, 0, arrayIndex );
}

225) Now add a new class ShoppingCartVM in Ecomm_Project2.Models  ViewModels 


Now add the two generic repository in ShoppingCartVM.cs 

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

namespace Ecomm_Project2.Models.ViewModels
{
public class ShoppingCartVM
{
public IEnumerable<ShoppingCart> ListCart { get; set; }
public OrderHeader OrderHeader { get; set; }
}
}

226) Now write the code in Index action of CartController.cs file for get the data from
multiple tables in the Details of the Product 

[BindProperty]
public ShoppingCartVM ShoppingCartVM { get; set; }

public IActionResult Index()


{
var claimIdentity = (ClaimsIdentity)User.Identity;
var claim = claimIdentity.FindFirst(ClaimTypes.NameIdentifier);
if (claim == null)
{
ShoppingCartVM = new ShoppingCartVM()
{
ListCart = new List<ShoppingCart>()
};
return View(ShoppingCartVM);
}

ShoppingCartVM = new ShoppingCartVM()


{
ListCart = _unitOfWork.ShoppingCart.GetAll(sp => sp.ApplicationUserId == claim.Value,
includeProperties: "Product"),
OrderHeader = new OrderHeader()
};
ShoppingCartVM.OrderHeader.OrderTotal = 0;
ShoppingCartVM.OrderHeader.ApplicationUser = _unitOfWork.ApplicationUser.FirstOrDefault
(u => u.Id == claim.Value, includeProperties: "Company");
foreach (var list in ShoppingCartVM.ListCart)
{
list.Price = SD.GetPriceBasedOnQuantity(list.Count, list.Product.Price, list.Product.Price50,
list.Product.Price100);
ShoppingCartVM.OrderHeader.OrderTotal += (list.Count * list.Price);
if(list.Product.Description==null)
{
list.Product.Description = "";
}
if(list.Product.Description.Length > 100)
{
list.Product.Description = list.Product.Description.Substring(0, 99) + "...";
}

}
return View(ShoppingCartVM);
}

227) Now add the Index view of the CartController.cs file 

@model Ecomm_Project2.Models.ViewModels.ShoppingCartVM
<form method="post">
<br />
@if (Model.ListCart.Count() > 0)
{
<div class="backgroundWhiteBorder">
<div class="container">
<div class="card">
<div class="card-header bg-dark text-light ml-0 row container">
<div class="col-6">
<i class="fa fa-shopping-cart"></i> &nbsp;
Shopping Cart
</div>
<div class="col-6 text-right">
<a asp-controller="Home" asp-action="Index" class="btn btn-outline-info btn-sm">Continue
Shopping</a>
</div>
</div>
<div class="card-body">
@foreach (var item in Model.ListCart)
{
var amount = item.Price * item.Count;
<div class="row">
<div class="d-none d-lg-block col-lg-1 text-center py-2">
<img src="@item.Product.ImageUrl" class="rounded" width="100%" />
</div>
<div class="col-12 text-sm-center col-lg-6 text-lg-left">
<h6>@item.Product.Title</h6>
<p><small>@Html.Raw(item.Product.Description)</small></p>
</div>
<div class="col-12 text-sm-center col-lg-5 text-lg-right row">
<div class="col-4 text-md-right" style="padding-top:5px;">
<h6>@item.Price<span class="text-muted">x</span>@item.Count = @amount</h6>
</div>
<div class="col-6 col-sm-4 col-lg-6">
<div class="float-right mx-1">
<a asp-action="plus" asp-route-id="@item.Id" class="btn btn-primary">
<i class="fas fa-plus"></i>
</a>
</div>
<div class="float-right mx-1">
<a asp-action="minus" asp-route-id="@item.Id" class="btn btn-danger">
<i class="fas fa-minus"></i>
</a>
</div>
</div>
<div class="col-2 col-sm-4 col-lg-2 text-right">
<a asp-action="delete" asp-route-id="@item.Id" class="btn btn-outline-danger">
<i class="fas fa-trash"></i>
</a>
</div>
</div>
</div>
}

<hr />
<div class="row">
<div class="col-12 col-md-6 offset-md-6 col-lg-4 offset-lg-8 pr-4">
<ul class="list-group">
<li class="list-group-item d-flex justify-content-between bg-light">
<span class="text-info"> Total (USD)</span>
<strong class="text-info">$ <span id="txtOrderTotal">@Model.OrderHeader.OrderTotal</span></strong>
</li>
</ul>
</div>
</div>
</div>
<div class="card-footer">
<div class="card-footer row">

<div class="col-sm-12 col-lg-4 col-md-6 offset-lg-8 offset-md-6 ">

<a asp-action="Summary" asp-controller="Cart" asp-area="Customer" class="btn btn-success form-


control">Summary</a>
</div>
</div>
</div>
</div>
</div>
</div>
}
else
{
<p class="text-danger"> No Items in the Cart!!</p>
}

</form>

228) Now write the code for increment/ decrement and delete of the item quantity in
CartController 

public IActionResult plus(int id)


{
var cart = _unitOfWork.ShoppingCart.FirstOrDefault(sc => sc.Id == id);
cart.Count += 1;
_unitOfWork.Save();
return RedirectToAction(nameof(Index));
}
public IActionResult minus(int id)
{
var cart = _unitOfWork.ShoppingCart.FirstOrDefault(sc => sc.Id == id);
if(cart.Count == 1)
{
cart.Count = 1;
}
else
{
cart.Count -= 1;
}
_unitOfWork.Save();
return RedirectToAction(nameof(Index));
}
public IActionResult delete(int id)
{
var cart = _unitOfWork.ShoppingCart.FirstOrDefault(sc => sc.Id == id);
_unitOfWork.ShoppingCart.Remove(cart);
_unitOfWork.Save();

// session
var claimIdentity = (ClaimsIdentity)User.Identity;
var claim = claimIdentity.FindFirst(ClaimTypes.NameIdentifier);
if(claim != null)
{
var count = _unitOfWork.ShoppingCart.GetAll(sc => sc.ApplicationUserId ==
claim.Value).ToList().Count;
HttpContext.Session.SetInt32(SD.Ss_CartSessionCount, count);
}
return RedirectToAction(nameof(Index));

After delete the item 

229) Now add write the code of Summary in CartController. So create the View of Summary 

public IActionResult Summary()


{
var claimIdentity = (ClaimsIdentity)User.Identity;
var claim = claimIdentity.FindFirst(ClaimTypes.NameIdentifier);
ShoppingCartVM = new ShoppingCartVM()
{
ListCart = _unitOfWork.ShoppingCart.GetAll(sc => sc.ApplicationUserId == claim.Value,
includeProperties: "Product"),
OrderHeader = new OrderHeader()
};
ShoppingCartVM.OrderHeader.ApplicationUser = _unitOfWork.ApplicationUser.FirstOrDefault
(u => u.Id == claim.Value, includeProperties: "Company");

foreach (var list in ShoppingCartVM.ListCart)


{
list.Price = SD.GetPriceBasedOnQuantity(list.Count, list.Product.Price,
list.Product.Price50, list.Product.Price100);
ShoppingCartVM.OrderHeader.OrderTotal += (list.Price * list.Count);
list.Product.Description = SD.ConvertToRawHtml(list.Product.Description);
}
ShoppingCartVM.OrderHeader.Name = ShoppingCartVM.OrderHeader.ApplicationUser.Name;
ShoppingCartVM.OrderHeader.PhoneNumber = ShoppingCartVM.OrderHeader.ApplicationUser.PhoneNumber;
ShoppingCartVM.OrderHeader.StreetAddress =
ShoppingCartVM.OrderHeader.ApplicationUser.StreetAddress;
ShoppingCartVM.OrderHeader.State = ShoppingCartVM.OrderHeader.ApplicationUser.State;
ShoppingCartVM.OrderHeader.City = ShoppingCartVM.OrderHeader.ApplicationUser.City;
ShoppingCartVM.OrderHeader.PostalCode = ShoppingCartVM.OrderHeader.ApplicationUser.PostalCode;
return View(ShoppingCartVM);
}

@model Ecomm_Project2.Models.ViewModels.ShoppingCartVM
<form method="post">
<br />
<div class="backgroundWhiteBorder">
<div class="container">
<div class="card">
<div class="card-header bg-dark text-light ml-0 row container">
<div class="col-6">
<i class="fa fa-shopping-cart"></i> &nbsp;
Order Summary
</div>
<div class="col-6 text-right">
<a class="btn btn-outline-info btn-sm" asp-action="Index">Back to Cart</a>
</div>
</div>
<div class="card-body">
<div class="container rounded p-2">
<div class="row">
<div class="col-12 col-lg-6 pb-4">
<div class="row">
<h4 class="d-flex justify-content-between align-items-center mb-3">
<span class="text-info">PickUp Details:</span>
</h4>
</div>
<div class="row my-1">
<div class="col-3">
<label>Name</label>
</div>
<div class="col-9">
<input type="text" asp-for="OrderHeader.Name" class="form-control" />
</div>
</div>
<div class="row my-1">
<div class="col-3">
<label>Phone</label>
</div>
<div class="col-9">
<input type="text" asp-for="OrderHeader.PhoneNumber" class="form-control" />
</div>
</div>
<div class="row my-1">
<div class="col-3">
<label>Street Address</label>
</div>
<div class="col-9">
<input type="text" asp-for="OrderHeader.StreetAddress" class="form-control" />
</div>
</div>
<div class="row my-1">
<div class="col-3">
<label>City</label>
</div>
<div class="col-9">
<input type="text" asp-for="OrderHeader.City" class="form-control" />
</div>
</div>
<div class="row my-1">
<div class="col-3">
<label>State</label>
</div>
<div class="col-9">
<input type="text" asp-for="OrderHeader.State" class="form-control" />
</div>
</div>
<div class="row my-1">
<div class="col-3">
<label>Postal Code</label>
</div>
<div class="col-9">
<input type="text" asp-for="OrderHeader.PostalCode" class="form-control" />
</div>
</div>
</div>
<div class="col-12 col-lg-5 offset-lg-1">
<h4 class="d-flex justify-content-between align-items-center mb-3">
<span class="text-info">Order Summary:</span>
</h4>
<ul class="list-group mb-3">
<li class="list-group-item d-flex justify-content-between">
<div>
<h6 class="my-0">--TITLE--</h6>
<small class="text-muted">Quantity: --COUNT--</small>
</div>
<span class="text-muted">$ --PRICE* COUNT--</span>
</li>
<li class="list-group-item d-flex justify-content-between bg-light">
<small class="text-info">Total (USD)</small>
<strong class="text-info">$--GRAND TOTAL--</strong>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="card-footer">
<div class="row">
<div class="col-12 col-md-8 pt-2">
<p style="color:maroon; font-size:14px;">Estimate Arrival Date:
@DateTime.Now.AddDays(7).ToShortDateString() - @DateTime.Now.AddDays(14).ToShortDateString()</p>
</div>
<div class="col-12 col-md-4">

<button type="submit" value="Place Order" class="btn btn-success form-


control">Place Order</button>
</div>
</div>
</div>
</div>
</div>
</div>
</form>

230) Write the code for Order Summary details in Summary.cshtml file 

231) Now write the code for Place Order data submit on button click in CartController.cs

[HttpPost]
[AutoValidateAntiforgeryToken]
[ActionName("Summary")]
public IActionResult SummaryPost()
{
var claimsIdentity = (ClaimsIdentity)User.Identity;
var claim = claimsIdentity.FindFirst(ClaimTypes.NameIdentifier);

ShoppingCartVM.OrderHeader.ApplicationUser = _unitOfWork.ApplicationUser.
FirstOrDefault(u => u.Id == claim.Value, includeProperties: "Company");

ShoppingCartVM.ListCart = _unitOfWork.ShoppingCart.GetAll(sc => sc.ApplicationUserId ==


claim.Value,
includeProperties: "Product");

ShoppingCartVM.OrderHeader.PaymentStatus = SD.PaymentStatusPending;
ShoppingCartVM.OrderHeader.OrderStatus = SD.OrderStatusPending;
ShoppingCartVM.OrderHeader.OrderDate = DateTime.Now;
ShoppingCartVM.OrderHeader.ApplicationUserId = claim.Value;
_unitOfWork.OrderHeader.Add(ShoppingCartVM.OrderHeader);
_unitOfWork.Save();

foreach(var list in ShoppingCartVM.ListCart)


{
list.Price = SD.GetPriceBasedOnQuantity(list.Count, list.Product.Price, list.Product.Price50,
list.Product.Price100);
OrderDetails orderDetails = new OrderDetails()
{
ProductId = list.ProductId,
OrderHeaderId = ShoppingCartVM.OrderHeader.Id,
Price = list.Price,
Count = list.Count
};
ShoppingCartVM.OrderHeader.OrderTotal += (list.Price * list.Count);
_unitOfWork.OrderDetail.Add(orderDetails);
_unitOfWork.Save();
}
_unitOfWork.ShoppingCart.RemoveRange(ShoppingCartVM.ListCart);
_unitOfWork.Save();
HttpContext.Session.SetInt32(SD.Ss_CartSessionCount, 0);
return RedirectToAction("OrderConfirmation", "Cart",
new { id = ShoppingCartVM.OrderHeader.Id });
}

232) Now write add the View of OrderConfirmation in CartController.cs 

Now write the code of Order Confirmation 

@model int
<div class="container row">
<div class="col-12 text-center">
<h1 class="text-primary text-center">Order Submitted Successfully</h1><br />
<img src="~/images/success.webp" width="50%" />
</div>
<div class="col-12 text-center" style="color:green">
<br />
Thank you for your order! <br />
We have received your order and we will send a follow up email shortly!
<br />
Your Order Number is :@Model
</div>
</div>

233) Now for payment gateway firstly we create an account in Stripe.com website 
By these steps we can create a new account.
234) Now create a new class StripeSettings in Ecomm_Project2.Utility 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace Ecomm_Project2.Utility
{
public class StripeSettings
{
public string Publishablekey { get; set; }
public string Secretkey { get; set; }
}
}

235) Now go to appsettings.json and add these keys in it 

236) Now go to the main project and right click on it and install the Stripe package 

237) Now go to the Startup.cs file add these services at here 


238) Now go to the Summary.cshtml and add the Stripe Payment gateway 

@*Stripe *@
@{
var orderTotalAmount = Model.OrderHeader.OrderTotal * 100;
}
<script src="https://checkout.stripe.com/checkout.js"
class="stripe-button"
data-key="@Stripe.Value.Publishablekey"
data-amount="@orderTotalAmount"
data-name="Book Shopping Project"
data-description="Get Your Book Now"
data-locale="auto"
data-label="Place Order"
data-allow-remeber-me="false"
data-image="https://www.shutterstock.com/image-photo/businessman-pressing-on-virtual-screen-260nw-
489207220.jpg">
</script>

239) Now add the stripe token for user security checking in the CartController 
Firstly, add the stripe token as a parameter 

#region Stripe
if (stripeToken == null)
{
ShoppingCartVM.OrderHeader.PaymentDueDate = DateTime.Now.AddDays(30);
ShoppingCartVM.OrderHeader.PaymentStatus = SD.PaymentStatusDelayPayment;
ShoppingCartVM.OrderHeader.OrderStatus = SD.OrderStatusApproved;
}
else
{
// payment process
var options = new ChargeCreateOptions()
{
Amount = Convert.ToInt32(ShoppingCartVM.OrderHeader.OrderTotal),
Currency = "usd",
Description = "Order Id : " + ShoppingCartVM.OrderHeader.Id,
Source = stripeToken
};
//Payment
var service = new ChargeService();
Charge charge = service.Create(options);
if (charge.BalanceTransactionId == null)
ShoppingCartVM.OrderHeader.PaymentStatus = SD.PaymentStatusRejected;
else
ShoppingCartVM.OrderHeader.TransactionId = charge.BalanceTransactionId;

if(charge.Status.ToLower() == "succeeded")
{
ShoppingCartVM.OrderHeader.PaymentStatus = SD.PaymentStatusApproved;
ShoppingCartVM.OrderHeader.OrderStatus = SD.OrderStatusApproved;
ShoppingCartVM.OrderHeader.OrderDate = DateTime.Now;
}
_unitOfWork.Save();
}
#endregion
240) Now for hide the Place Order button in Order Summary go to Summary.cshtml, add a
JavaScript code 

241) Now add a new class EmailSettings in Ecomm_Project2.Utility 

Now add the following models 

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

namespace Ecomm_Project2.Utility
{
public class EmailSettings
{
public String PrimaryDomain { get; set; }
public int PrimaryPort { get; set; }
public String SecondaryDomain { get; set; }
public int SecondaryPort { get; set; }
public String UsernameEmail { get; set; }
public String UsernamePassword { get; set; }
public String FromEmail { get; set; }
public String ToEmail { get; set; }
public String CcEmail { get; set; }

}}

242) Now go to the appsettings.json and add email information 

243) Now add these services in Startup.cs file 

244) Now generate the email message and subjects in EmailSender.cshtml


Ecomm_project2.Utility 

using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Text;
using System.Threading.Tasks;

namespace Ecomm_Project2.Utility
{
public class EmailSender : IEmailSender
{
private EmailSettings _emailSettings { get; }
public EmailSender(IOptions<EmailSettings> emailSettings)
{
_emailSettings = emailSettings.Value;
}
public Task SendEmailAsync(string email, string subject, string htmlMessage)
{
Execute(email, subject, htmlMessage).Wait();
return Task.FromResult(0);
}
public async Task Execute(string email, string subject, string message)
{
try
{
string toEmail = string.IsNullOrEmpty(email) ? _emailSettings.ToEmail : email;
MailMessage mail = new MailMessage()
{
From = new MailAddress(_emailSettings.UsernameEmail, "My Email Name..")
};
mail.To.Add(toEmail);
mail.CC.Add(_emailSettings.CcEmail);
mail.Subject = "Book Shopping App : " + subject;
mail.Body = message;
mail.IsBodyHtml = true;
mail.Priority = MailPriority.High;
using (SmtpClient smtp = new SmtpClient(_emailSettings.PrimaryDomain,
_emailSettings.PrimaryPort))
{
smtp.Credentials = new NetworkCredential(_emailSettings.UsernameEmail,
_emailSettings.UsernamePassword);
smtp.EnableSsl = true;
await smtp.SendMailAsync(mail);
}

}
catch (Exception ex)
{
string str = ex.Message;
}
}
}
}

245) Now go to the Register.cshtml.cs and make the code un-comment which was comment
before 

246) Now go to the CartController.cs and write the code for email sender confirmation 
247) Now go to the Index.cshtml page and write the confirmation condition at here 

248) Now go to CartController.cs file and add the EmailConfirmation in IndexPost action 
Project 2 (WEB API/ API)

1) Click on new project 

2) Choose ASP.NET CORE WEB API option and click Next 

3) Next 

4) Now install these package 


5) Now make a connection string in appsettings.json 

6) Now create a new folder Models in main project and add a new class NationalPark.cs in this
folder 

Write the models name in it 

using System;
using System.ComponentModel.DataAnnotations;

namespace NationalParkAPI.Models
{
public class NationalPark
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string State { get; set; }
public byte[] Picture { get; set; }
public DateTime Created { get; set; }
public DateTime Established { get; set; }
}
}

7) Now add a new folder Data in main project and a new class ApplicationdbContext in it 
using Microsoft.EntityFrameworkCore;
using NationalParkAPI.Models;

namespace NationalParkAPI.Data
{
public class ApplicationDbContext:DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options):base(options)
{

}
public DbSet<NationalPark> NationalParks { get; set; }
}
}
8) Now add the connection string in Startup.cs file 

9) Now add the migration and update database 

10) Now add a new class Trail in Models folder 

using NationalParkAPI.Migrations;
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace NationalParkAPI.Models
{
public class Trail
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Distance { get; set; }
[Required]
public string Elevation { get; set; }
public DateTime DateCreated { get; set; }
public enum DifficultyType { Easy, Moderate, Difficult }
public DifficultyType Difficulty { get; set; }
public int NationalParkId { get; set; }
[ForeignKey("NationalParkId")]
public NationalPark NationalPark { get; set; }
}
}

11) Now add this Model class Trail class in ApplicationDbContext class 
12) Now again add the migration and update database 

13) Now create a new Repository folder in main project and a sub folder IRepository in it.
14) Now add a new Interface type class INationalParkRepository in IRepository folder.

INationalParkRepository.cs

using NationalParkAPI.Models;
using System.Collections.Generic;

namespace NationalParkAPI.Repository.IRepository
{
public interface INationalParkRepository
{
ICollection<NationalPark> GetNationalParks();
NationalPark GetNationalPark(int nationalParkId);
bool NationalParkExists(int nationalParkId);
bool NationalParkExists (string nationalParkName);
bool CreateNationalPark(NationalPark nationalPark);
bool UpdateNationalPark(NationalPark nationalPark);
bool DeleteNationalPark(NationalPark nationalPark);
bool Save();
}
}
15) Now add a new class NationalParkRepository in Repository folder.

NationalParkRepository.cs

using Microsoft.AspNetCore.Authentication;
using NationalParkAPI.Data;
using NationalParkAPI.Models;
using NationalParkAPI.Repository.IRepository;
using System.Collections.Generic;
using System.Linq;

namespace NationalParkAPI.Repository
{
public class NationalParkRepository : INationalParkRepository
{
private readonly ApplicationDbContext _context;
public NationalParkRepository(ApplicationDbContext context)
{
_context = context;

}
public bool CreateNationalPark(NationalPark nationalPark)
{
_context.NationalParks.Add(nationalPark);
return Save();
}

public bool DeleteNationalPark(NationalPark nationalPark)


{
_context.NationalParks.Remove(nationalPark);
return Save();
}

public ICollection<NationalPark> GetNationalPark()


{
return _context.NationalParks.ToList();
}

public NationalPark GetNationalPark(int nationalParkId)


{
return _context.NationalParks.Find(nationalParkId);
}

public bool NationalParkExists(int nationalParkId)


{
return _context.NationalParks.Any(np => np.Id == nationalParkId);
}

public bool NationalParkExists(string nationalParkName)


{
return _context.NationalParks.Any(np => np.Name == nationalParkName);
}

public bool Save()


{
return _context.SaveChanges() == 1 ? true : false;
}

public bool UpdateNationalPark(NationalPark nationalPark)


{
_context.NationalParks.Update(nationalPark);
return Save();
}
}
}

16) Now create a interface type class ITrailRepository in the IRepository folder.

ITrailRepository.cs

using NationalParkAPI.Models;
using System.Collections;
using System.Collections.Generic;

namespace NationalParkAPI.Repository.IRepository
{
public interface ITrailRepository
{
ICollection<Trail> GetTrails();
ICollection<Trail> GetTrailsInNationalPark(int nationalParkId);
Trail GetTrail(int trailId);
bool TrailExists(int trailId);
bool TrailExists(string trailName);
bool CreateTrail(Trail trail);
bool UpdateTrial(Trail trail);
bool DeleteTrail(Trail trail);
bool Save();
}
}

17) Now add new class TrailRepository in Repository folder.

TrailRepository.cs

using Microsoft.EntityFrameworkCore;
using NationalParkAPI.Data;
using NationalParkAPI.Models;
using NationalParkAPI.Repository.IRepository;
using System;
using System.Collections.Generic;
using System.Linq;

namespace NationalParkAPI.Repository
{
public class TrailRepository : ITrailRepository
{
private readonly ApplicationDbContext _context;
public TrailRepository(ApplicationDbContext context)
{
_context = context;
}

public bool CreateTrail(Trail trail)


{
_context.Trails.Add(trail);
return Save();
}

public bool DeleteTrail(Trail trail)


{
_context.Trails.Remove(trail);
return Save();
}

public Trail GetTrail(int trailId)


{
return _context.Trails.Find(trailId);
}

public ICollection<Trail> GetTrails()


{
return _context.Trails.ToList();
}

public ICollection<Trail> GetTrailsInNationalPark(int nationalParkId)


{
return _context.Trails.Include(t => t.NationalPark).Where(t => t.NationalParkId ==
nationalParkId).ToList();
}

public bool Save()


{
return _context.SaveChanges() == 1 ? true : false;
}

public bool TrailExists(int trailId)


{
return _context.Trails.Any(t => t.Id == trailId);
}

public bool TrailExists(string trailName)


{
return _context.Trails.Any(t => t.Name == trailName);
}

public bool UpdateTrial(Trail trail)


{
_context.Trails.Update(trail);
return Save();
}
}
}
18) Now add these classes in the Startup.cs class for make these DI (Dependency Injection) 

19) Now create two new classes to NationalPark class and Trail Class in new sub folder DTOs of
Models folder for make them more secure through DTOs (Data Transfer Objects).
DTO means  it adds a new layer between the User and Database(db and controller) for make
more secure. In it the only models/columns are add those are represent to the user and other
will be hide.
{
Db  model  rep  dto  controller (Frontend)

Controller  dto  rep  model  db (Backend)

// db  model  dto
// dto  model  db

NationalParkDto.cs

using System;
using System.ComponentModel.DataAnnotations;
using System.Security.Cryptography;

namespace NationalParkAPI.Models.DTOs
{
public class NationalParkDto
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string State { get; set; }
public byte[] Picture { get; set; }
public DateTime Created { get; set; }
public DateTime Established { get; set; }
}
}

TrailDto.cs

using System.ComponentModel.DataAnnotations;
using static NationalParkAPI.Models.Trail;

namespace NationalParkAPI.Models.DTOs
{
public class TrailDto
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Distance { get; set; }
[Required]
public string Elevation { get; set; }
public DifficultyType Difficulty { get; set; }
public int NationalParkId { get; set; }
public NationalPark NationalPark { get; set; }
}
}

20) Now add a new folder DTOMapping in the main Project.


Now in this new folder add a new class MappingProfile.There will be required a new package;
Now add the above class in the below class for mapping.

MappingProfile.cs

using AutoMapper;
using NationalParkAPI.Models;
using NationalParkAPI.Models.DTOs;
using System.Net.Sockets;
using System.Security.Cryptography;

namespace NationalParkAPI.DTOMapping
{
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<NationalParkDto, NationalPark>().ReverseMap();
CreateMap<TrailDto, Trail>().ReverseMap();
}
}
}

21) Firstlly download the AutoMapper package.

22) Now go to the Startup.cs file and add the MappingProfile.cs in Mapping 
23) Now add a new API Controller-Empty NationalParkController in the controller folder of main
project 

NationalParkController.cs

using AutoMapper;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using NationalParkAPI.Models;
using NationalParkAPI.Models.DTOs;
using NationalParkAPI.Repository.IRepository;
using System.Linq;

namespace NationalParkAPI.Controllers
{
[Route("api/NationalPark")]
[ApiController]
public class NationalParkController : Controller
{
private readonly INationalParkRepository _nationalParkRepository;
private readonly IMapper _mapper;
public NationalParkController(INationalParkRepository nationalParkRepository, IMapper mapper)
{
_nationalParkRepository = nationalParkRepository;
_mapper = mapper;
}
[HttpGet]
public IActionResult GetNationalParks()
{
var nationalParkListDto = _nationalParkRepository.GetNationalParks().ToList().
Select(_mapper.Map<NationalPark, NationalParkDto>);
return Ok(nationalParkListDto); // 200
}
[HttpGet("{nationalParkId:int}",Name = "GetNationalPark")]
public IActionResult GetNationalPark(int nationalParkId)
{
var nationalPark = _nationalParkRepository.GetNationalPark(nationalParkId);
if (nationalPark == null) return NotFound(); //404
var nationalParkDto = _mapper.Map<NationalParkDto>(nationalPark);
return Ok(nationalParkDto); //200
}
[HttpPost]
public IActionResult CreateNationalPark([FromBody]NationalParkDto nationalParkDto)
{
if(nationalParkDto == null) return BadRequest(ModelState);
if (_nationalParkRepository.NationalParkExists(nationalParkDto.Name))
{
ModelState.AddModelError("", "National Park already in DB");
return StatusCode(StatusCodes.Status500InternalServerError);
}
if (!ModelState.IsValid) return BadRequest(ModelState);

var nationalPark = _mapper.Map<NationalParkDto,NationalPark>(nationalParkDto);


if (!_nationalParkRepository.CreateNationalPark(nationalPark))
{
ModelState.AddModelError("", $"Something went wrong while save data :{nationalPark.Name}");
return StatusCode(StatusCodes.Status500InternalServerError);
}
//return Ok();
return CreatedAtRoute("GetNationalPark", new { nationalParkId = nationalPark.Id },
nationalPark);//201
}
[HttpPut]
public IActionResult UpdateNationalPark([FromBody] NationalParkDto nationalParkDto)
{
if (nationalParkDto == null) return BadRequest(ModelState); //400
if (!ModelState.IsValid) return BadRequest(ModelState);
var nationalPark = _mapper.Map<NationalPark>(nationalParkDto);
if (!_nationalParkRepository.UpdateNationalPark(nationalPark))
{
ModelState.AddModelError("", $"Something went wrong while update the data :
{nationalPark.Name}");
return StatusCode(StatusCodes.Status500InternalServerError);
}
return NoContent(); //204
}
[HttpDelete("{nationalParkId:int}")]
public IActionResult DeleteNationalPark(int nationalParkId)
{
if (!_nationalParkRepository.NationalParkExists(nationalParkId))
{
return NotFound();
}
var nationalPark = _nationalParkRepository.GetNationalPark(nationalParkId);
if (nationalPark == null) return NotFound();
if (!_nationalParkRepository.DeleteNationalPark(nationalPark))
{
ModelState.AddModelError("", $"somthing went wrong while delete the data:
{nationalPark.Name}");
return StatusCode(StatusCodes.Status500InternalServerError);
}
return Ok();
}
}
}
24) Now again add a new empty API controller of Trail in Controller folder 

TrailController.cs

using AutoMapper;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using NationalParkAPI.Models;
using NationalParkAPI.Models.DTOs;
using NationalParkAPI.Repository.IRepository;
using System.Linq;

namespace NationalParkAPI.Controllers
{
[Route("api/Trail")]
[ApiController]
public class TrailController : ControllerBase
{
private readonly ITrailRepository _trailRepository;
private readonly IMapper _mapper;
public TrailController(ITrailRepository trailRepository, IMapper mapper)
{
_trailRepository = trailRepository;
_mapper = mapper;
}
[HttpGet]
public IActionResult GetTrails()
{
return Ok(_trailRepository.GetTrails().ToList().Select(_mapper.Map<Trail, TrailDto>));
}
[HttpGet("{trailId=int}", Name = "GetTrail")]
public IActionResult GetTrail(int trailId)
{
var trail = _trailRepository.GetTrail(trailId);
if (trail == null) return NotFound();
return Ok(_mapper.Map<TrailDto>(trail));
}
[HttpPost]
public IActionResult CreateTrail([FromBody] TrailDto trailDto)
{
if (trailDto == null) return BadRequest(ModelState);
if (!ModelState.IsValid) return NotFound();
if (_trailRepository.TrailExists(trailDto.Name))
{
ModelState.AddModelError("", $"Trail already in db:{trailDto.Name}");
return StatusCode(StatusCodes.Status500InternalServerError);
}
var trail = _mapper.Map<Trail>(trailDto);
if (!_trailRepository.CreateTrail(trail))
{
ModelState.AddModelError("", $"Somthing went wrong while save the trail : {trail.Name}");
return StatusCode(StatusCodes.Status500InternalServerError);
}
//return Ok();
return CreatedAtRoute("GetTrail", new { trailId = trail.Id }, trail);
}
[HttpPut]
public IActionResult UpdateTrail([FromBody] TrailDto trailDto)
{
if (trailDto == null) return BadRequest();
if (!ModelState.IsValid) return BadRequest();

var trail = _mapper.Map<Trail>(trailDto);


if (!_trailRepository.UpdateTrial(trail))
{
ModelState.AddModelError("", $"Something went wrong while update the trail: {trail.Name}");
return StatusCode(StatusCodes.Status500InternalServerError);
}
return NoContent();
}
[HttpDelete("{trailId:int}")]
public IActionResult DeleteTrail(int trailId)
{
if (!_trailRepository.TrailExists(trailId)) return NotFound();
var trailInDb = _trailRepository.GetTrail(trailId);
if (trailInDb == null) return NotFound();
if (!_trailRepository.DeleteTrail(trailInDb))
{
ModelState.AddModelError("", $"Somthing went wrong while delete the trail : {trailInDb.Name}");
return StatusCode(StatusCodes.Status500InternalServerError);
}
return Ok();
}
}
}

25) Now add a new project ParkWebApp in the Main Solution as steps below 
26) Now add the for multiple page start go to the solution and do some settings 

27) Now go to the ParkWebApp and a new class SD.cs 

namespace ParkWebApp
{
public static class SD
{
public static string APIBaseUrl = "https://localhost:44388/";
public static string NationalParkAPIPath = APIBaseUrl + "api/NationalPark/";
public static string TrailAPIPath = APIBaseUrl + "api/Trail/";
}
}

28) Now add the new NationalPark.cs class in the models folder of the ParkWebApp project 

using System.ComponentModel.DataAnnotations;
using System;

namespace ParkWebApp.Models
{
public class NationalPark
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string State { get; set; }
public byte[] Picture { get; set; }
public DateTime Created { get; set; }
public DateTime Established { get; set; }
}
}
29) Now again add a new class Trail.cs in Models folder of the ParkWebApp project 

using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
using System;
namespace ParkWebApp.Models
{
public class Trail
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Distance { get; set; }
[Required]
public string Elevation { get; set; }
public DateTime DateCreated { get; set; }
public enum DifficultyType { Easy, Moderate, Difficult }
public DifficultyType Difficulty { get; set; }
[Display(Name="National Park")]
public int NationalParkId { get; set; }
public NationalPark NationalPark { get; set; }
}
}

30) Now add a new Repository folder in the ParkWebApp project. And also add new subfolder in the
Repository folder 

31) Now for creating a Generic repository add a new interface IRepository in the subfolder of
Repository folder IRepository, at ParkWebApp

using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace ParkWebApp.Repository.IRepository
{
public interface IRepository<T> where T:class
{
Task<T> GetAsync(string url, int id);
Task<IEnumerable<T>> GetAllAsync(string url);
Task<bool> CreateAsync(string url, T objToCreate);
Task<bool> UpdateAsync(string url, T objToUpdate);
Task<bool> DeleteAsync(string url, int id);
}

32) Now add a new class Repository in the Repository folder of ParkWebApp project 

using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Identity;
using Newtonsoft.Json;
using ParkWebApp.Repository.IRepository;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace ParkWebApp.Repository
{
public class Repository<T> : IRepository<T> where T : class
{
private readonly IHttpClientFactory _httpClientFactory;
public Repository(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}

public async Task<bool> CreateAsync(string url, T objToCreate)


{
var request = new HttpRequestMessage(HttpMethod.Post, url);
if (objToCreate != null)
{
request.Content = new StringContent(JsonConvert.SerializeObject(objToCreate),
Encoding.UTF8, "application/json");
}
var client = _httpClientFactory.CreateClient();
HttpResponseMessage response = await client.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.Created)
return true;
else
return false;
}

public async Task<bool> DeleteAsync(string url, int id)


{
var request = new HttpRequestMessage(HttpMethod.Delete, url + id.ToString());
var client = _httpClientFactory.CreateClient();
HttpResponseMessage response = await client.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
return true;
else
return false;
}

public async Task<IEnumerable<T>> GetAllAsync(string url)


{
var request = new HttpRequestMessage(HttpMethod.Get, url);
var client = _httpClientFactory.CreateClient();
HttpResponseMessage response = await client.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
var jsonString = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<IEnumerable<T>>(jsonString);
}
return null;

public async Task<T> GetAsync(string url, int id)


{
var request = new HttpRequestMessage(HttpMethod.Get,url + id.ToString());
var client = _httpClientFactory.CreateClient();
HttpResponseMessage response = await client.SendAsync(request);
if(response.StatusCode == System.Net.HttpStatusCode.OK)
{
var jsonString = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(jsonString);
}
return null;
}

public async Task<bool> UpdateAsync(string url, T objToUpdate)


{
var request = new HttpRequestMessage(HttpMethod.Put, url);
if (objToUpdate != null)
{
request.Content = new StringContent(JsonConvert.SerializeObject(objToUpdate),
Encoding.UTF8, "application/json");
}
var client = _httpClientFactory.CreateClient();
HttpResponseMessage response = await client.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.NoContent)
{
return true;
}
else
return false;
}

}
}

33) Now add a new interface INationalParkRepository in IRepository folder in ParkWebApp project

using ParkWebApp.Models;

namespace ParkWebApp.Repository.IRepository
{
public interface INationalParkRepository:IRepository<NationalPark>
{
}
}

34) Now add a new NationalParkRepository in Repository folder of ParkWebApp project 

using ParkWebApp.Models;
using ParkWebApp.Repository.IRepository;
using System.Net.Http;

namespace ParkWebApp.Repository
{
public class NationalParkRepository : Repository<NationalPark>, INationalParkRepository
{
private readonly IHttpClientFactory _httpClientFactory;
public NationalParkRepository(IHttpClientFactory httpClientFactory) : base(httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
}
}

35) Now again add a new Interface ITrailRepository in IRepository folder of ParkWebApp project

using ParkWebApp.Models;

namespace ParkWebApp.Repository.IRepository
{
public interface ITrailRepository : IRepository<Trail>
{
}
}

36) Now add a new class TrailRepository in Repository folder of ParkWebApp project 

using ParkWebApp.Models;
using ParkWebApp.Repository.IRepository;
using System.Net.Http;

namespace ParkWebApp.Repository
{
public class TrailRepository : Repository<Trail>, ITrailRepository
{
private readonly IHttpClientFactory _httpClientFactory;
public TrailRepository(IHttpClientFactory httpClientFactory) : base(httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
}
}
37) Now add these Interfaces and Classes in Startup.cs of ParkWebApp 

38) Now add a new controller NationalParkController in Controllers folder of ParkWebApp project

using Microsoft.AspNetCore.Mvc;
using ParkWebApp.Repository.IRepository;

namespace ParkWebApp.Controllers
{
public class NationalParkController : Controller
{
private readonly INationalParkRepository _nationalParkRepository;
public NationalParkController(INationalParkRepository nationalParkRepository)
{
_nationalParkRepository = nationalParkRepository;
}

public IActionResult Index()


{
return View();
}
}
}
39) Now add the view of Index 
When we add the Razor View of the Index action then maybe show an error to adding this, it
is because of package and their version problems. So, to fix this problem add these packages
in ParkWebApp project with proper version. As shown below -

40) Now add the National Park controller in the navbar of Home page, so go the _Layout.cshtml
file 
41) Now add the links of CSS and JavaScript in the _Layout.cshtml file 

42) Now write the code of Index page in Index.cshtml 

<div class="row">
<div class="col-6">
<h2 class="text-primary">National Park List</h2>
</div>
<div class="col-6 text-right">
<a class="btn btn-info" asp-action="Upsert">
<i class="fas fa-plus"></i>&nbsp;New National Park
</a>
</div>
</div>
<div class="p-3">
<table id="tblData" class="table table-striped table-active table-bordered">
<thead>
<tr>
<th>Name</th>
<th>State</th>
<th>Action</th>
</tr>
</thead>
</table>
</div>

43) Now write the code for get the API data in the table at the NationalParkController.cs file
in the ParkWebApp project 

44) Now add the new js file nationalPark.js in the js folder of wwwroot folder of the ParkWebApp
project 
45) Now write the code to show the data in list/table in nationalPark.js file 

var dataTable;
$(document).ready(function () {
loadDataTable();

})
function loadDataTable() {
dataTable = $('#tblData').DataTable({
"ajax": {
"url": "NationalPark/GetAll",
"type": "GET",
"datatype": "json"
},
"columns": [{ "data": "name", "width": "40%" },{ "data": "state", "width": "40%" },
{
"data": "id", "render": function (data) {
return `
<div class="text-center">
<a href="NationalPark/Upsert/${data}" class = "btn btn-info">
<i class="fas fa-edit"></i>
</a>
<a class = "btn btn-danger" onclick=Delete("/NationalPark/Delete/${data}")>
<i class="fas fa-trash-alt"></i>
</a>
</div>

`;
}
}
]})}
function Delete(url) {
swal({
text: "Delete Information !!",
title: "Want to delete data ?",
icon: "warning",
buttons: true,
dangerModel: true
}).then((willDelete) => {
if (willDelete) {
$.ajax({
url: url,
type: "DELETE",
success: function (data) {
if (data.success) {
toastr.success(data.message);
dataTable.ajax.reload();
}
else {
toastr.error(data.message);
}
}
})
}})}

46) Now add this js file in the index.cshtml file 

47) Now write the code of Upsert in NationalParkController.cs 


48) Now add the View for Upsert and write the code at here for Create and Update 

@model ParkWebApp.Models.NationalPark
@{
ViewData["Title"] = "Upsert";
var title = Model.Id != 0 ? "Edit National Park" : "New National Park";
var saveupdate = Model.Id != 0 ? "Update" : "Save";
}
<form method="post" enctype="multipart/form-data">
@if (Model.Id != 0)
{
<input type="hidden" asp-for="@Model.Id" />
}
<div class="row border">
<div class="col-10 border-bottom p-2 m-2">
<h1 class="text-primary">@title</h1>
</div>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="col-8 p-2">
<div class="form-group row">
<div class="col-4">
<label asp-for="Name"></label>
</div>
<div class="col-8">
<input asp-for="Name" class="form-control" />
<span class="text-danger" asp-validation-for="Name"></span>
</div>
</div>
<div class="form-group row">
<div class="col-4">
<label asp-for="State"></label>
</div>
<div class="col-8">
<input asp-for="State" class="form-control" />
<span class="text-danger" asp-validation-for="State"></span>
</div>
</div>
<div class="form-group row">
<div class="col-4">
<label asp-for="Picture"></label>
</div>
<div class="col-8">
@*<input asp-for="Name" class="form-control" />*@
<input type="file" name="files" id="projectImage" asp-for="Picture" class="form-control"
multiple />
<span class="text-danger" asp-validation-for="Picture"></span>
</div>
</div>
<div class="form-group row">
<div class="col-4">
<label asp-for="Established"></label>
</div>
@{
var dateEst = "";
if (Model.Id != 0)
{
dateEst = Model.Established.ToShortDateString();
}
}
<div class="col-8">
<input type="text" id="datepickers" value="@dateEst" asp-for="Established" class="form-
control" />

<span class="text-danger" asp-validation-for="Established"></span>


</div>
</div>
<div class="form-group row">
<div class="col-4 offset-4">
<button type="submit" class="btn btn-success form-control">
@saveupdate
</button>
</div>
<div class="col-4">
<a asp-action="Index" class="btn btn-info form-control">
Back to List
</a>
</div>
</div>
</div>
<div class="col-4">
@if (Model.Picture != null)
{
var base64 = Convert.ToBase64String(Model.Picture);
@*var imgSrc = string.Format("data:image/jpg;base64,{0}", base64);*@
var imgSrc = string.Format("data:image;base64,{0}", base64);
<img src="@imgSrc" width="100%" />
}
else{
<p>No Image Found!</p>
}
</div>
</div>
</form>
@section scripts{
<partial name="_ValidationScriptsPartial" />
<script>
$(function () {
$("#datepickers").datepicker({
changeMonth: true,
changeYear: true
})
})
</script>
}

49) Now write the code for Update the information in NationalParkController.cs 

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Upsert(NationalPark nationalPark)
{
if (ModelState.IsValid)
{
var files = HttpContext.Request.Form.Files;
if (files.Count > 0)
{
byte[] p1 = null;
using (var fs1 = files[0].OpenReadStream())
{
using (var ms1 = new MemoryStream())
{
fs1.CopyTo(ms1);
p1 = ms1.ToArray();
}
}
nationalPark.Picture = p1;
}
else
{
var npInDb = await _nationalParkRepository.GetAsync(SD.NationalParkAPIPath,
nationalPark.Id);
nationalPark.Picture = npInDb.Picture;
}
if (nationalPark.Id == 0)
await _nationalParkRepository.CreateAsync(SD.NationalParkAPIPath, nationalPark);
else
await _nationalParkRepository.UpdateAsync(SD.NationalParkAPIPath, nationalPark);
return RedirectToAction(nameof(Index));
}
else
return View(nationalPark);
}

50) Now write the Delete code in the NationalParkController.cs 


51) Now add the new empty TrailController in the Controllers folder of ParkWebApp project 

using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Serialization;
using ParkWebApp.Repository.IRepository;

namespace ParkWebApp.Controllers
{
public class TrailController : Controller
{
private readonly ITrailRepository _trailRepository;
public TrailController(ITrailRepository trailRepository)
{
_trailRepository = trailRepository;
}

public IActionResult Index()


{
return View();
}
}
}
52) Now add the new Razor View of Index 

53) Now add the Trail at navbar in _Layout.cshtml 


<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Trail" asp-action="Index">Trail</a>
</li>

54) Now write the code for Get the data in the Json form in the TrailController.cs file 

55) Now write the code for show the data in table from the Json form in the trail.js file. So
create the trail.js file in the js folder at wwwroot folder in ParkWebApp project 

var dataTable;
$(document).ready(function () {
loadDataTable();

})
function loadDataTable() {
dataTable = $('#tblData').DataTable({
"ajax": {
"url": "Trail/GetAll",
"type": "GET",
"datatype": "json"
},
"columns": [
{ "data": "nationalPark.name", "width": "20%" },
{ "data": "name", "width": "20%" },
{ "data": "distance", "width": "20%" },
{ "data": "elevation", "width": "20%" },
{
"data": "id", "render": function (data) {
return `
<div class="text-center">
<a href="Trail/Upsert/${data}" class = "btn btn-info">
<i class="fas fa-edit"></i>
</a>
<a class="btn btn-danger" onclick=Delete("Trail/Delete/${data}")>
<i class="fas fa-trash-alt"></i>
</a>
</div>

`;
}
}
]
})
}
function Delete(url) {
/*debugger;*/
swal({
text: "Delete Information !!",
title: "Want to delete data ?",
buttons: true,
icon: "warning",
dangerModel: true
}).then((willDelete) => {
if (willDelete) {
$.ajax({
url: url,
type: "DELETE",
success: function (data) {
if (data.success) {
toastr.success(data.message);
dataTable.ajax.reload();
}
else {
toastr.error(data.message);
}
}
})
}
})
}

56) Now write the code in the Index.cshtml 

<div class="row border rounded">


<div class="col-9">
<h2 class="text-primary">Trail List</h2>
</div>
<div class="col-3 p-2">
<a class="btn btn-info form-control" asp-action="Upsert">
<i class="fas fa-plus"></i>&nbsp;New Trail
</a>
</div>
</div>
<br />
<br />
<div class="p-3">
<table id="tblData" class="table table-striped table-active table-bordered">
<thead>
<tr>
<th>National Park</th>
<th>Trail Name</th>
<th>Distance</th>
<th>Elevation</th>
<th>Actions</th>
</tr>
</thead>
</table>
</div>
@section scripts{
<script src="~/js/trail.js"></script>
}
57) Now add a ViewModel in Trail for get data from multiple models, because at one time the view
can access one model that’s why create a view model for send the multiple data at a time 

So, create a new sub folder ViewModels in the Models folder. In this folder add a new class
TrailVM 

using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.VisualBasic.FileIO;
using System.Collections;
using System.Collections.Generic;

namespace ParkWebApp.Models.ViewModels
{
public class TrailVM
{
public Trail Trail { get; set; }
public IEnumerable<SelectListItem> nationalParkList { get; set; }
}
}

58) Now add the INationalParkRepository in TrailController 

59) Now write the code for Insert the data in TrailController.cs 

60) Before write the code of Upsert firstly we add a include method in the NationalParkAPI
project, TrialRepository 

61) Now add the View of Upsert 

@model ParkWebApp.Models.ViewModels.TrailVM
@{
ViewData["Title"] = "Upsert";
var title = Model.Trail.Id != 0 ? "Edit Trail" : "New Trail";
var saveupdate = Model.Trail.Id != 0 ? "Update" : "Save";
}
<form method="post" asp-action="Upsert">
<div class="row border">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
@if (Model.Trail.Id != 0)
{
<input type="hidden" asp-for="@Model.Trail.Id" />
}
<div class="col-8 border-bottom">
<h2 class="text-primary">@title</h2>
</div>
</div>
<div class="col-8">
<div class="form-group row p-2 m-2">
<div class="col-4">
<label asp-for="Trail.NationalParkId"></label>
</div>
<div class="col-8">
@Html.DropDownListFor(m => Model.Trail.NationalParkId,
Model.nationalParkList,"Select National Park",
new {@class = "form-control"})
<span asp-validation-for="Trail.NationalParkId" class="text-danger"></span>
</div>
</div>
<div class="form-group row p-2 m-2">
<div class="col-4">
<label asp-for="Trail.Name"></label>
</div>
<div class="col-8">
<input asp-for="Trail.Name" class="form-control" />
<span asp-validation-for="Trail.Name" class="text-danger"></span>
</div>
</div>
<div class="form-group row p-2 m-2">
<div class="col-4">
<label asp-for="Trail.Difficulty"></label>
</div>
<div class="col-8">
<select asp-for="Trail.Difficulty" asp-
items="Html.GetEnumSelectList<ParkWebApp.Models.Trail.DifficultyType>()"
class="form-control"></select>
<span asp-validation-for="Trail.Difficulty" class="text-danger"></span>
</div>
</div>
<div class="form-group row p-2 m-2">
<div class="col-4">
<label asp-for="Trail.Distance"></label>
</div>
<div class="col-8">
<input asp-for="Trail.Distance" class="form-control" />
<span asp-validation-for="Trail.Distance" class="text-danger"></span>
</div>
</div>
<div class="form-group row p-2 m-2">
<div class="col-4">
<label asp-for="Trail.Elevation"></label>
</div>
<div class="col-8">
<input asp-for="Trail.Elevation" class="form-control" />
<span asp-validation-for="Trail.Elevation" class="text-danger"></span>
</div>
</div>
<div class="form-group row p-2 m-2">
<div class="col-4 offset-4">
<button type="submit" class="btn btn-success form-control">@saveupdate</button>
</div>
<div class="col-4">
<a asp-action="Index" class="btn btn-primary form-control">Back to List</a>
</div>
</div>
</div>
</form>
@section scripts{
<partial name="_ValidationScriptsPartial" />
}

62) Now write the code of Save and Update of Trail information in TrailController.cs 

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Upsert(TrailVM trailVM)
{
if (ModelState.IsValid)
{
if (trailVM.Trail.Id == 0)
await _trailRepository.CreateAsync(SD.TrailAPIPath, trailVM.Trail);
else
await _trailRepository.UpdateAsync(SD.TrailAPIPath, trailVM.Trail);
return RedirectToAction(nameof(Index));
}
else
{
IEnumerable<NationalPark> nationalParks = await _nationalParkRepository.
GetAllAsync(SD.NationalParkAPIPath);
trailVM = new TrailVM()
{
Trail = new Trail(),
nationalParkList = nationalParks.Select(np => new SelectListItem()
{
Text = np.Name,
Value = np.Id.ToString()
})
};
return View(trailVM);
}
}
63) Now write the Delete API code of Trail data in the TrailController.cs 

64) Now to show the all data on the Home page in ParkWebApp project, we create a Index view. But
firstly, we add the INationalParkRepository and ITrailRepository in the HomeControlle 

65) Now add a new class as a ViewModel IndexVM in the Models  ViewModels 

using Microsoft.AspNetCore.Cors.Infrastructure;
using Microsoft.AspNetCore.Routing.Tree;
using System.Collections;
using System.Collections.Generic;

namespace ParkWebApp.Models.ViewModels
{
public class IndexVM
{
public IEnumerable<NationalPark> NationalParkList { get; set; }
public IEnumerable<Trail> TrailList { get; set; }
}
}
66) Now add the this IndexVM class in the HomeControler.cs 

67) Now add the View of Index 

@model ParkWebApp.Models.ViewModels.IndexVM
@{
ViewData["Title"] = "Home Page";
}

<div class="container backgroundWhite pb-4">


<div class="card border">
@foreach (var nationalPrak in Model.NationalParkList)
{
<hr />
<div class="card-header bg-dark text-light ml-0 row container">
<div class="col-12 col-md-6">
<h3 class="text-warning">@nationalPrak.Name</h3>
</div>
<div class="col-12 col-md-6 text-md-right">
<h3 class="text-warning">State : @nationalPrak.State</h3>
</div>
</div>
<div class="card-body">
<div class="container rounded p-2">
<div class="row">
<div class="col-12 col-lg-8">
<div class="row">
<div class="col-12">
<h3 style="color:#bbb9b9">Established:@nationalPrak.Established.Year </h3>
</div>
<div class="col-12">
<table class="table table-striped" style="border:1px solid #808080 ">
<thead>
<tr class="table-secondary">
<th>
Trail
</th>
<th>Distance</th>
<th>Elevation Gain</th>
<th>Difficulty</th>
</tr>
</thead>
<tbody>
@{
var trailList = Model.TrailList.Where(t => t.NationalParkId ==
nationalPrak.Id);
// var trailEmpty = trailList == null ? "no data found" : "";

foreach (var trail in trailList)


{
if (trail != null)
{
<tr>
<td>@trail.Name</td>
<td>@trail.Distance</td>
<td>@trail.Elevation</td>
<td>@trail.Difficulty</td>
</tr>
}
//else
//{
// foreach (var trailemp in trailEmpty)
// {

// <tr>
// <td>@trailemp</td>
// <td>@trailemp</td>
// <td>@trailemp</td>
// <td>@trailemp</td>
// </tr>
// }
//}
}

</tbody>
</table>
</div>
</div>
</div>
<div class="col-12 col-lg-4 text-center">
@{
var base64 = Convert.ToBase64String(nationalPrak.Picture);
var finalStr = string.Format("data:image;base64,{0}", base64);
}
<img src="@finalStr" class="card-img-top p-2 rounded" width="100%" />
</div>
</div>
</div>
<br />
</div>

</div>

</div>

68) Now go to the NationalParkAPI project, here in the Models folder, add a new model class User
in it 

using Microsoft.EntityFrameworkCore.Query;
using System.ComponentModel.DataAnnotations.Schema;

namespace NationalParkAPI.Models
{
public class User
{
public int Id { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string Role { get; set; }
[NotMapped]
public string Token { get; set; }
}
}
69) Now add this Model in the ApplicationDbContext 

70) Now add the Migration and Update the database 


71) Now add a new Interface IUserRepository in the Repository  IRepository folder 

using NationalParkAPI.Models;

namespace NationalParkAPI.Repository.IRepository
{
public interface IUserRepository
{
bool IsUniqueUser(string username);
User Authenticate(string userName, string password);
User Register(string userName, string password);
}
}
72) Now add the new class UserRepository in the Repository folder 

using NationalParkAPI.Data;
using NationalParkAPI.Models;
using NationalParkAPI.Repository.IRepository;
using System.Linq;

namespace NationalParkAPI.Repository
{
public class UserRepository : IUserRepository
{
private readonly ApplicationDbContext _context;
private readonly AppSettings _appSettings;
public UserRepository(ApplicationDbContext context, IOptions<AppSettings> appSettings)
{
_context = context;
_appSettings = appSettings.Value;

}
public User Authenticate(string userName, string password)
{
var userInDb = _context.Users.FirstOrDefault(u => u.UserName == userName && u.Password ==
password);
if (userInDb == null) return null;

userInDb.Password = "";
return userInDb;
}

public bool IsUniqueUser(string username)


{
var user = _context.Users.FirstOrDefault(u => u.UserName == username);
if (user == null)
return true;
else
return false;
}

public User Register(string userName, string password)


{
User user = new User()
{
UserName = userName,
Password = password,
Role = "Admin"
};
_context.Users.Add(user);
_context.SaveChanges();
return user;
}
}
}
73) Now add these IUserRepository and UserRepository in the Startup.cs file 

74) Now add a new API controller UserController in the Controllers folder of the NationalParkAPI
project 
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using NationalParkAPI.Models;
using NationalParkAPI.Repository.IRepository;

namespace NationalParkAPI.Controllers
{
[Route("api/user")]
[ApiController]
public class UserController : Controller
{
private readonly IUserRepository _userRepository;
public UserController(IUserRepository userRepository)
{
_userRepository = userRepository;
}
[HttpPost("register")]
public IActionResult Register([FromBody] User user)
{
if (ModelState.IsValid)
{
var isUniqueUser = _userRepository.IsUniqueUser(user.UserName);
if (!isUniqueUser)
return BadRequest("User in use!!");
var userInfo = _userRepository.Register(user.UserName, user.Password);
if (userInfo == null) return BadRequest();
}
return Ok();
}
}
}

75) Now add a new class UserVM in the Models folder, because there is no need to show all the
Information of the user during the login time. So for hide other information here we create
the a new model 

namespace NationalParkAPI.Models
{
public class UserVM
{
public string UserName { get; set; }
public string Password { get; set; }
}
}

76) Now create a new Authentication type method in the UserCotroller for check user correct or
not 

77) Now for authorized the all pages here we add the Authorize in the NationalParkController and
TrailController 
78) Now for apply the JWT (JSON WEB TOKEN) in the project here firstly we install the JWT
package 

79) Now to get the token key there is add a new class AppSettings in the NationalParkAPI project

namespace NationalParkAPI
{
public class AppSettings
{
public string Secret { get; set; }
}
}

80) Now go to the appsettings.json file and create a new token id at here 

81) Now go to the Startup page and add the JWT Authentication 

82) Now go to the UserRepository login system add this JWT token for authorization by the token

83) Now add a new class ConfigureSwaggerOptions in the NationalPark project for configure the
authorization with the token 

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Collections.Generic;

namespace NationalParkAPI
{
public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions>
{
public void Configure(SwaggerGenOptions options)
{
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT Authorization header using the Bearer Scheme,\r\n" +
"Enter 'Bearer' [space] and then your token in the text input below \r\n" +
"Example:Bearer 123456abcde \r\n" +
"Name:Authorization\r\n" +
"In header",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer"

});

options.AddSecurityRequirement(new OpenApiSecurityRequirement() {
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
},
Scheme = "oauth2",
Name = "Bearer",
In = ParameterLocation.Header
},
new List<string>()
}
});
}
}
}
84) Now add this class in the Startup.cs file and also add the Authentication method

You might also like