1670 assignment 2 (pass) 1670 assignment 2 (pass) 1670 assignment 2 (pass) 1670 assignment 2 (pass) 1670 assignment 2 (pass) 1670 assignment 2 (pass) 1670 assignment 2 (pass) 1670 assignment 2 (pass) 1670 assignment 2 (pass) 1670 assignment 2 (pass) 1670 assignment 2 (pass) FPT GREENWICH
Introduction
In the application development section, I will outline the initial directory structure of the program, followed by detailed explanations and source code examples Additionally, I will provide a screenshot of the user interface of the completed product I will also demonstrate how to manage the source code using GitHub or GitLab through screenshots Finally, I will present an image illustrating the deployment of the application using IIS or Azure.
This article will begin with an assessment of the application's performance, followed by an evaluation of its compliance with requirements and identification of areas for improvement Key factors influencing program performance will be analyzed, and the original directory structure will be reviewed for future development The section will also include explanations and source code examples, along with screenshots of the user interface of the completed product Additionally, it will demonstrate source code management using GitHub or GitLab, and conclude with an image illustrating the deployment of the application using IIS or Azure.
The app review will begin with an assessment of its performance, followed by an evaluation of whether it meets all necessary requirements or needs improvements Additionally, I will analyze the factors influencing the app's performance and assess its advantages and disadvantages.
Formal questionnaire to review the business application, problem definition statement, proposed
In this section, the jobs that users can use are based on their account roles Here is a list of jobs sorted by role:
- Administrator role: Login, log out, register for Owner account, manage Owner and User accounts, reset Owner and User accounts, manage category browsing
- Owner: Log in, log out, manage books(CRUD), request category, manage orders
-Customers: Login, log out, register, account management, cart management, book preview, book lookup, see About page
- Guest: book preview, book lookup, see About page, register
Questionnaire about the FPT bookstore application:
No./Function Question Date Answer Date
1 Log-in Whether or not users may log in using accounts from other websites, such as Facebook or Google
Because, as far as I'm aware, the system does not currently have such a function
Will that feature ever be upgraded on your system?
20/2/2023 Currently, we are unable to add such functionality to the system, but we will work to do so in the future
If your system has a feature to save account information, do you use user cookies?
20/2/2023 To make logging in the next time quicker, our system can save the user's account
We prioritize your privacy by only storing your registered account information and not utilizing cookies, allowing you to use our system with complete confidence.
2 Register Although your system has a function for account authentication, in my opinion it is not very good Will your system ever be updated to send authentication by email?
21/3/2023 To ensure the safety of the users of our system, we will work to implement such function in the near future
Can the administrator make changes to the data that other users have submitted?
On March 21, 2023, our administrators have the authority to modify information about other users, which includes the ability to delete accounts However, we require user consent to take such actions; without permission, we lack the legal right to intervene.
4 Searching Can I find a book by looking up the author or publisher as well as the book's description if I'm looking for one but don't know the title?
21/3/2023 It goes without saying that our system will utilize the information provided by the user to search the system for pertinent book goods
5 Role Are functions like customer accounts usable by accounts with higher permissions, and vice versa, are services like customer accounts usable by accounts with higher permissions?
On March 22, 2023, our technology facilitates the decentralization of accounts, enabling access to advanced features The administrator account holds the highest level of permissions, followed by the business owner account, and then the standard user account.
Higherpermissioned accounts can utilize the features of lowerpermissioned accounts, while lowerpermissioned accounts cannot use the features of senior accounts.
Application development
Entity Relationship Diagram (ERD)
The diagram below displays entity relationship of the FPTBook web-based application:
Figure 1 Entity Relationship Diagram (ERD)
Develop a functional business application
There are some tools, techniques and methodologies that I use to develop the FPT bookstore application:
Visual Studio is a powerful Integrated Development Environment (IDE) created by Microsoft, designed for developing a wide range of applications, including GUI, console, web, mobile, and cloud applications This versatile IDE supports both managed and native code, utilizing various Microsoft development platforms such as Windows Store and Windows API It is not limited to a specific programming language, allowing developers to write code in C#, C++, Visual Basic, Python, JavaScript, and more, with support for 36 different languages Available for both Windows and macOS, Visual Studio has evolved since its initial release in 1997, with the latest version being 15.0, launched in March.
Visual Studio 2017, also known as Visual Studio 2017, supports NET Framework versions ranging from 3.5 to 4.7 While previous versions included support for Java, the latest release does not offer any support for the Java programming language.
Data consists of vast collections of facts and figures, readily accessible to users through the internet and various sources To effectively manipulate this data, Structured Query Language (SQL) was introduced years ago Numerous versions of SQL are available from different organizations, and this article will focus on the version offered by Microsoft.
Microsoft SQL Server or MS SQL Server for short is the query language provided for data definition and manipulation
SQL Server is a Relational Database Management Systems which was developed and marketed by the Microsoft company
SQL and SQL servers are built as two layers where the SQL server is on the top for interacting with the relational databases
MS SQL Server also has T-SQL or Transact-SQL and the main focus of T-SQL is to handle the transactions
As it is a Microsoft’s developed system, it worked only on Microsoft’s environment until it was made available on Linux platforms in the year 2016
HTML, or Hyper Text Markup Language, is a markup language essential for designing web pages It establishes links between web pages through hypertext and defines the structure of documents using tags The latest version, HTML5, enhances document markup and introduces application programming interfaces (APIs) and the Document Object Model (DOM).
CSS, or Cascading Style Sheets, is essential for styling web pages, enhancing their visual appeal It simplifies the process of presentation by allowing styles to be applied independently of the underlying HTML structure This flexibility makes it easier to create attractive and well-organized web content.
Bootstrap is a widely-used, free, and open-source framework designed for building responsive websites and web applications It stands out as the leading HTML, CSS, and JavaScript toolkit for creating mobile-first designs that function seamlessly across various browsers, including Internet Explorer, Firefox, and Chrome, as well as on devices of all sizes, from desktops to smartphones Originally developed by Mark Otto and Jacob Thornton at Twitter, Bootstrap has since evolved into a collaborative open-source project.
ASP.NET Core is a free, open-source development platform designed for creating modern cloud-based applications across Windows, Linux, and macOS It has been enhanced for speed, scalability, and modernity, making NET Core a significant contribution from Microsoft, released under the MIT License Key features include cross-platform support and a focus on performance.
Multiple environments and development mode etc
The Model-View-Controller (MVC) framework is a widely adopted architectural pattern that divides an application into three key components: Model, View, and Controller This separation allows for the isolation of business logic from the presentation layer, enhancing the development process Originally utilized for desktop graphical user interfaces, MVC has evolved into a standard framework for web development, facilitating the creation of scalable and extensible projects, as well as being applicable in mobile app design.
The Model-View-Controller (MVC) design pattern, developed by Trygve Reenskaug, aims to address the challenges users face when managing extensive and complex data sets By dividing a large application into distinct sections, each with a specific function, MVC enhances organization and usability.
It provides a clear separation of business logic, Ul logic, and input logic
It offers full control over your HTML and URLs which makes it easy to design web application architecture
It is a powerful URL-mapping component using which we can build applications that have comprehensible and searchable URLs
It supports Test Driven Development (TDD)
The MVC framework includes the following 3 components:
The controller serves as the intermediary between the views and the model, facilitating their interconnection It focuses on processing business logic and incoming requests without managing data logic directly, instructing the model on necessary actions By manipulating data through the Model component, the controller interacts with the View to produce the final output.
The Model component encompasses all data-related logic that users interact with, representing the data exchanged between the View and Controller components, as well as any business logic It is responsible for adding or retrieving data from the database and responds to requests from the Controller, which cannot directly interact with the database By interacting with the database, the Model provides the necessary data back to the Controller.
The View component is essential for managing the user interface logic of the application, generating a user-friendly interface It relies on data collected by the model component, but this data is accessed indirectly through the controller, ensuring that the View interacts solely with the controller.
Figure 8Model-View-Controller (MVC) framework
Folder structure of the application
Our website FPT Book project is built on the ASP.NET Core MVC structure paradigm, which is comprised of Models, Views, and Controllers:
Overall structure of the project: This folder contains the whole code source for the FPTBook project
Application data files are stored in the Areas/Identity folder, while the Data folder of the database contains all account-related data Additionally, the Pages folder includes the output for the registration page, navigation, and account authentication.
The Controllers folder contains directories that describe operations like adding, modifying, removing, and reading particular model information:
Controllers folder: This folder is used to store the controllers of use cases such as Admin, Book, Cart, Home, Order, Category
Constants folders: This directory is used to declare model of Constants
Models folders: This folder is used to declare the Category, Book, BookDisplayModel, Order, CartDetail, ShoppingCart, OrderDetail,ErrorViewModel, Owner
Views folders: This folder is used to save the interfaces of use cases such as Admin, Book, Cart, Category, Home, Order, Shared
In the Views folder, it will contain folders to clearly show the interfaces of each specific model:
Admin folders: The interfaces of the Admin as: Index, RegisterOwner, RequestCategory, ShowOwner, ShowUser
Book folders: The interfaces of the Book as: Create, Edit, Delete
Cart folders: The interfaces of the Cart as : GetUserCart
Category folders: The interfaces of the Category as: Create, Edit, Delete
Home folders: The interfaces of the Home as : BookDetail, Index, ShowBook
Order folders: The interfaces of the Order as : GetOrder, OrderDetail
Shared folder: In this folder, it will save the navigation interface after login as well as the partial login page of the FPTBook project
Figure 22 Shared folder wwwroot folder: This is the folder to store the source css, fonts, js, libraries as well as images (in uploads folder) to serve the website
Code source samples of the application with an explanation
To launch a website with the ASP.NET Core framework, we initiated a project named FPTBook_v3 using the command “dotnet new mvc -o FPTBook_v3” and trusted the HTTPS development certificate with “dotnet dev-certs https trust.” Subsequently, we developed essential models for the project, including Category, Book, BookDisplayModel, Order, CartDetail, ShoppingCart, OrderDetail, ErrorViewModel, and Owner.
The table blow shows code source of files in Models folder:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int book_Id { get; set; } [Required] public string book_Title { get; set; } [Required] public DateTime publication_date { get; set; } public string? book_ImagURL { get; set; }
[Required] public string book_Description { get; set; } [Required] public double book_Price { get; set; } [Required] public int book_Quantity { get; set; } public int cate_Id { get; set; }
[ForeignKey("cate_Id")] public virtual Category? category { get; set; } public virtual ICollection? OrderDetails { get; set; }
[NotMapped] public IFormFile? book_Img { get; set; } }
The `BookDisplayModel` class is designed to manage a collection of books and categories, featuring properties such as `Books`, `Categorys`, `STerm`, and `GenreId` The `STerm` property is initialized to an empty string, while `GenreId` defaults to zero Additionally, the class includes an implicit operator to convert from a `DTOs.BookDisplayModel`, although this functionality is not yet implemented.
The article outlines a data model for a shopping cart system, featuring essential properties such as an identifier (Id), a required ShoppingCartId, a required BookId, a required Quantity, and a required UnitPrice Each property is crucial for managing the items within the shopping cart effectively.
[ForeignKey("BookId")] public virtual Book? Book { get; set; }
[ForeignKey("ShoppingCartId")] public ShoppingCart ShoppingCart { get; set; } } }
[Required] public int cate_Id { get; set; } [Required]
[Display(Name = "cate_Name")] public string cate_Name { get; set; } [Required]
[Display(Name = "cate_Description")] public string cate_Description { get; set; } public string? cate_Status { get; set; } public virtual ICollection? Books { get; set; } } }
{ public string? RequestId { get; set; } public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); }
[Key] public int Id { get; set; } public string UserId { get; set; } [Required, Display(Name = "Create Date")] public DateTime CreateDate { get; set; } = DateTime.UtcNow; public List OrderDetail { get; set; }
[ForeignKey("UserId")] public virtual ApplicationUser? ApplicationUsers { get; set; } }
The class includes several required properties: an integer for the Order ID, an integer for the Book ID, an integer for the Quantity, and a double for the Unit Price Additionally, it contains references to the Order and Book objects.
[Required, Display(Name = "Name")] public string Name { get; set; }
[Required,Display(Name = "Email")] public string Email { get; set; }
[StringLength(10, ErrorMessage = "Phone number must have 10 digits", MinimumLength = 10)] public string Phone { get; set; }
[Required, Display(Name = "Image")] public string? Image { get; set; }
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[Display(Name = "Password")] public string Password { get; set; }
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] public string ConfirmPassword { get; set; } public IFormFile? Img { get; set; } }
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; }
[Required] public string UserId { get; set; } public ICollection CartDetails { get; set; } [ForeignKey("UserId")] public virtual ApplicationUser? ApplicationUsers { get; set; } } }
Views After creating models, we create files in the Views folder
Controllers Next, we develop file controllers to conduct the operations of each model, such as create, delete, edit, view, and so on in the Controllers folder
The table blow shows code source of files in Controllers folder:
{ [Authorize(Roles = "Admin")] public class AdminController : Controller { private readonly UserManager _userManager; private readonly ApplicationDbContext _db; private readonly IFileService _fileService; public
AdminController(ApplicationDbContext db, UserManager userManager,
} public IActionResult Index() { return View();
The ShowUser method retrieves a list of users from the database who have the role of "User " by joining the Users, UserRoles, and Roles tables This asynchronous task returns the filtered user data to the view for display.
The ShowOwner method retrieves a list of users with the role of "Owner" from the database by joining the Users, UserRoles, and Roles tables It uses asynchronous programming to fetch the data and returns the results to the view for display.
[Route("Admin/RequestCategory")] public IActionResult RequestCategory() { var category = _db.Categorys.Where(c => c.cate_Status ="processing").ToList(); return View(category);
30 public IActionResult Approval(int id) {
Category category = _db.Categorys.Find(id); if (category == null) { return RedirectToAction("RequestCategory");
} else { category.cate_Status = "processed";
_db.SaveChanges(); return RedirectToAction("RequestCategory");
[Route("Admin/RequestCategory/Reject")] public IActionResult Reject(int id) {
Category category = _db.Categorys.Find(id); if (category == null) { return RedirectToAction("RequestCategory");
_db.SaveChanges(); return RedirectToAction("RequestCategory");
[Route("Admin/RegisterOwner")] public async Task RegisterOwner() { return View();
[Route("Admin/RegisterOwner")] public async Task RegisterOwner(Owner owners) { if (ModelState.IsValid) { var owner = new ApplicationUser {
UserName = owners.Email, User_Name = owners.Name, Email = owners.Email, PhoneNumber = owners.Phone,
32 var resultt = _fileService.SaveImage(owners.Img) if (resultt.Item1 == 1) { var oldImage = owner.User_Img; owner.User_Img = resultt.Item2; if (oldImage == null) {
} } var result = await _userManager.CreateAsync(owner, owners.Password); if (result.Succeeded) { await _userManager.AddToRoleAsync(owner, Role.Owner.ToString()); return RedirectToAction("ShowOwner");
{ TempData["Fail"] = "RegisterOwner Fail!"; return RedirectToAction("RegisterOwner");
[Authorize(Roles = "Owner")] public class BookController : Controller { private readonly ApplicationDbContext _db; private readonly ILogger _logger; public BookController(ILogger
[Route("/Owner/Book")] public async Task Index() {
IEnumerable books = await GetBooks(); logger,
IEnumerable categorys = await _db.Categorys.ToListAsync(); ;
Models.BookDisplayModel bookModel = new Models.BookDisplayModel
{ Books = books, Categorys = categorys }; return View(bookModel);
[Route("/Owner/Book/Create")] public IActionResult Create() {
ViewData["Cate_Id"] = new SelectList(_db.Categorys.Where(c
=> c.cate_Status == "processed").ToList(), "cate_Id", "cate_Name"); return View();
[Route("/Owner/Book/Create")] public IActionResult Create(Book book) { if (ModelState.IsValid) { try
{ string uniqueFileName = UploadFile(book); book.book_ImagURL = uniqueFileName; if (book.book_Quantity < 0 || book.book_Price < 0) {
TempData["Fail"] = "Quantity and Price must be greater than 0";
SelectList(_db.Categorys.Where(c => c.cate_Status ="processed").ToList(), "cate_Id", "cate_Name"); return View(book);
_db.SaveChanges(); return RedirectToAction("Index");
SelectList(_db.Categorys.Where(c => c.cate_Status
"processed").ToList(), "cate_Id", "cate_Name"); TempData["Error"] = ""; return
[Route("/Owner/Book/Edit/{id:}")]
36 public IActionResult Edit(int id) {
Book book = _db.Books.Find(id); if (book == null) { return RedirectToAction("Index");
} ViewData["Cate_Id"] = new SelectList(_db.Categorys,
"cate_Id", "cate_Name"); return View(book);
[Route("/Owner/Book/Edit/{id:}")] public IActionResult Edit(int id, Book book,string img) { book.book_Id = id; if (ModelState.IsValid) { try
{ if (book.book_Img == null) { book.book_ImagURL = img; if (book.book_Quantity < 0 || book.book_Price
< 0) { TempData["Fail"] = "Quantity and Price must be greater than 0";
ViewData["Cate_Id"] = new SelectList(_db.Categorys.Where(c => c.cate_Status ="processed").ToList(), "cate_Id", "cate_Name"); return View(book);
{ string uniqueFileName = UploadFile(book); book.book_ImagURL = uniqueFileName; if (book.book_Quantity < 0 || book.book_Price
< 0) { TempData["Fail"] = "Quantity and Price must be greater than 0";
ViewData["Cate_Id"] = new SelectList(_db.Categorys.Where(c => c.cate_Status ="processed").ToList(), "cate_Id", "cate_Name"); return View(book);
37 img = Path.Combine("wwwroot", "uploads", img); FileInfo infor = new FileInfo(img); if (infor
{ System.IO.File.Delete(img); infor.Delete();
ViewData["Cate_Id"] = new SelectList(_db.Categorys.Where(c => c.cate_Status =
"processed").ToList(), "cate_Id", "cate_Name"); return View(book);
[Route("/Owner/Book/Delete/{id:}")] public ActionResult Delete(int id, string img) {
Book book = _db.Books.Find(id); if (book == null) { return RedirectToAction("Index");
} else { img = Path.Combine("wwwroot", "uploads", img);
FileInfo infor = new FileInfo(img); if (infor != null) { System.IO.File.Delete(img); infor.Delete();
_db.SaveChanges(); return RedirectToAction("Index");
} } public string UploadFile(Book book) { string uniqueFileName = null; if (book.book_Img != null) { var ext = Path.GetExtension(book.book_Img.FileName); var allowedExtensions = new string[] { ".jpg", ".png"
".jpeg" }; if (!allowedExtensions.Contains(ext)) ,
{ string msg = string.Format("Only {0} extensions are allowed", string.Join(",", allowedExtensions)); throw new Exception(msg);
} string uploadsFoder = Path.Combine("wwwroot",
"uploads"); uniqueFileName = Guid.NewGuid().ToString() + book.book_Img.FileName; string filePath = Path.Combine(uploadsFoder, uniqueFileName); using (var fileStream = new FileStream(filePath, FileMode.Create)) { book.book_Img.CopyTo(fileStream);
} public async Task GetBooks() {
IEnumerable books = await (from book in _db.Books join genre in _db.Categorys on book.cate_Id equals genre.cate_Id select new Book
The article provides essential details about a book, including its ID, image URL, category, title, price, quantity, publication date, and description.
= book.book_Description } ).ToListAsync(); return books;
[Authorize(Roles = "User")] public class CartController : Controller { private readonly ApplicationDbContext _db; private readonly UserManager _userManager; private readonly IHttpContextAccessor _httpContextAccessor;
42 public CartController(ApplicationDbContext db, IHttpContextAccessor httpContextAccessor,
[Route("User/Cart/AddItem")] public async Task AddItem(int bookId, int qty 1, int redirect = 0) { var cartCount = await AddItemCart(bookId, qty); if (redirect == 0) return Ok(cartCount); return RedirectToAction("GetUserCart");
[Route("User/Cart/RemoveItem")] public async Task RemoveItem(int bookId) { var cartCount = await RemoveCartItem(bookId); return RedirectToAction("GetUserCart");
[Route("User/Cart/GetUserCart")] public async Task GetUserCart() { var cart = await GetCartItem(); return View(cart);
[Route("User/Cart/GetTotalItemInCart")] public async Task GetTotalItemInCart() { int cartItem = await GetCartItemCount(); return Ok(cartItem);
[Route("User/Cart/Checkout")] public async Task Checkout() { var isCheckedOut = await DoCheckout(); if (!isCheckedOut) { TempData["Quantity"] = "The number of products is not enough!"; return Redirect("~/User/Cart/GetUserCart");
{ TempData["Success"] = "Order Success"; return Redirect("~/User/Cart/GetUserCart");
To add an item to the cart, the method `AddItemCart` requires a book ID and quantity It first retrieves the user ID to ensure the user is logged in; if not, an exception is thrown The method then attempts to fetch the user's shopping cart, creating a new cart if none exists.
UserId = userId }; _db.ShoppingCarts.Add(cart);
} _db.SaveChanges(); var cartItem = _db.CartDetails FirstOrDefault(a => a.ShoppingCartId == cart.Id && a.BookId == bookId); if (cartItem is not null) {
_db.SaveChanges(); cartItem.Quantity += qty;
} else { var book = _db.Books.Find(bookId); cartItem = new CartDetail
{ BookId = bookId, ShoppingCartId = cart.Id, Quantity = qty,
UnitPrice = book.book_Price // it is a new line after update
} var cartItemCount = await GetCartItemCount(userId); return cartItemCount;
} public async Task RemoveCartItem(int bookId) {
//using var transaction = _db.Database.BeginTransaction(); string userId = GetUserId(); try
{ if (string.IsNullOrEmpty(userId)) throw new Exception("user is not logged-in"); var cart = await GetCart(userId); if (cart is null) throw new Exception("Invalid cart");
// cart detail section var cartItem = _db.CartDetails FirstOrDefault(a =>
47 a.ShoppingCartId == cart.Id && a.BookId == bookId); if (cartItem is null) throw new Exception("Not items in cart"); else if (cartItem.Quantity == 1) _db.CartDetails.Remove(cartItem); else cartItem.Quantity = cartItem.Quantity - 1;
} var cartItemCount = await GetCartItemCount(userId); return cartItemCount;
The method `GetCartItem` retrieves the shopping cart for a user by first obtaining the user ID If the user ID is invalid, an exception is thrown The method then queries the database for the shopping cart associated with the user, including details of the cart items and their respective book categories, and returns the shopping cart.
} public async Task GetCart(string userId) { var cart = await _db.ShoppingCarts.FirstOrDefaultAsync(x
} public async Task GetCartItemCount(string userId = "") { if (!string.IsNullOrEmpty(userId)) { userId = GetUserId();
} var data = await (from cart in _db.ShoppingCarts join cartDetail in _db.CartDetails
48 on cart.Id equals cartDetail.ShoppingCartId select new { cartDetail.Id } ).ToListAsync(); return data.Count;
The `DoCheckout` method initiates the checkout process by first verifying if the user is logged in; if not, it throws an exception It then retrieves the user's shopping cart and checks for its validity If the cart is empty or invalid, appropriate exceptions are raised Finally, an `Order` object is created with the user's ID and the current date.
_db.SaveChanges(); foreach (var item in cartDetail) { var orderDetail = new OrderDetail {
The code snippet adds order details to the database, including the BookId, OrderId, Quantity, and UnitPrice It checks the available quantity of the book in the inventory, and if the available quantity is less than the requested quantity, it returns false, indicating that the order cannot be fulfilled.
{ quantity.book_Quantity quantity.book_Quantity - item.Quantity;
} } private string GetUserId() { var principal = _httpContextAccessor.HttpContext.User; string userId = _userManager.GetUserId(principal); return userId;
{ [Authorize(Roles = "Owner")] public class CategoryController : Controller { private readonly ApplicationDbContext _db; public CategoryController(ApplicationDbContext db) {
[Route("/Owner/Category")] public IActionResult Index() {
IEnumerable ds = _db.Categorys.Where(c => c.cate_Status == "processed").ToList(); return View(ds);
[Route("/Owner/Category/Create")] public IActionResult Create() { return View();
51 public IActionResult Create(Category category) { if (ModelState.IsValid) { category.cate_Status = "Processing";
_db.SaveChanges(); return RedirectToAction("Index");
[Route("/Owner/Category/Edit/{id:}")] public IActionResult Edit(int id) {
Category category = _db.Categorys.Find(id); if (category == null) { return RedirectToAction("Index");
[Route("/Owner/Category/Edit/{id:}")] public IActionResult Edit(int id, Category category) { if (ModelState.IsValid) { category.cate_Id = id; category.cate_Status = "processed";
_db.SaveChanges(); return RedirectToAction("Index");
[Route("/Owner/Category/Delete/{id:}")] public ActionResult Delete(int id) {
Category category = _db.Categorys.Find(id); if (category == null) { return RedirectToAction("Index");
_db.SaveChanges(); return RedirectToAction("Index");
{ public class HomeController : Controller { private readonly ILogger _logger; private readonly ApplicationDbContext _db; public HomeController(ILogger logger, ApplicationDbContext db) {
[Route("Home/ShowBook")] public async Task ShowBook(string sterm = "", int genreId = 0)
IEnumerable books = await GetBooks(sterm, genreId); IEnumerable categorys = await _db.Categorys.Where(x => x.cate_Status == "processed").ToListAsync();
; Models.BookDisplayModel bookModel = new Models.BookDisplayModel
{ Books = books, Categorys = categorys, }; return View(bookModel);
[Route("/Book/Detail/{id:}")] public async Task BookDetail(int id) { if (id == null || _db.Books == null) { return NotFound();
{ var book = _db.Books.Include(x =>
53 x.category).FirstOrDefault(b => b.book_Id == id); if (book == null) { return NotFound();
} } } public async Task Index(string sterm = "", genreId = 0) { int
IEnumerable books = await IndexGetBook(sterm, genreId);
IEnumerable categorys = await _db.Categorys.Where(x => x.cate_Status == "processed").ToListAsync(); ; Models.BookDisplayModel bookModel = new Models.BookDisplayModel
{ Books = books, Categorys = categorys, }; return View(bookModel);
[ResponseCache(Duration = 0, Location ResponseCacheLocation.None, NoStore = true)] public IActionResult Error() { return View(new ErrorViewModel { RequestId Activity.Current?.Id ?? HttpContext.TraceIdentifier });
} public async Task Category() { return await _db.Categorys.ToListAsync();
} public async Task IndexGetBook(string sTerm
IEnumerable books = await (from book in _db.Books join genre in
The query retrieves a list of books from the database, filtering by category and title If the search term is empty or the book title starts with the search term, it fetches all relevant books Additionally, if a specific genre ID is provided and the search term is not null, it further narrows down the results to books that match both the genre ID and the exact title.
/*books = books.Where(a => a.book_Id = genreId).ToList();*/ } else if (genreId != 0 && sTerm == null) { books = await (from book in _db.Books
55 join genre in _db.Categorys on book.cate_Id equals genre.cate_Id where genre.cate_Id == genreId select book).ToListAsync();
} public async Task GetBooks(string sTerm "", int genreId = 0) {
IEnumerable books = await (from book in _db.Books join genre in
The query retrieves books from the database where the category ID matches the genre ID and the book title starts with a specified search term If a genre ID is provided and the search term is not null, it fetches books that belong to that genre and have an exact title match with the search term.
The code snippet filters books based on a specified genre ID If the genre ID is not zero and the search term is null, it retrieves a list of books that belong to the selected genre by joining the books with their corresponding categories in the database The results are then returned as a list asynchronously.
{ public class OrderController : Controller { private readonly ApplicationDbContext _db; private readonly IHttpContextAccessor _httpContextAccessor;
57 private readonly UserManager _userManager; public OrderController(ApplicationDbContext db, UserManager userManager,
[Route("/User/UserOrders")] public async Task UserOrders() { var userId = GetUserId(); if (string.IsNullOrEmpty(userId)) throw new Exception("User is not logged-in"); var orders = await _db.Orders
Include(x => x.OrderDetail) ThenInclude(x => x.Book) ThenInclude(x => x.category) Where(a => a.UserId == userId) ToListAsync(); return orders;
} private string GetUserId() { var principal = _httpContextAccessor.HttpContext.User; string userId = _userManager.GetUserId(principal); return userId;
[Route("/User/UserOrders/OrderDetail")] public async Task OrderDetail() { var orders = await UserOrders(); return View(orders);
[Route("Owner/GetOrder")] public async Task GetOrder() { var orders = await _db.Orders Include(x => x.ApplicationUsers) Include(x => x.OrderDetail) ThenInclude(x => x.Book) ThenInclude(x => x.category) ToListAsync(); return View(orders);
To connect the data to the database, we need to establish a connection to SQL Server by using a specific statement in the appsettings.json file.
Final screenshots of the application
There are all pages of my website and new frameworks (if they have changed):
Sign-in: Login: For a better look at the Login page, the title has been removed The navigation pages have been removed
The registration process has been updated with the information fields now positioned in the center of the page, an enlarged input column, and a vertical layout for the info column Additionally, the home address field has been removed.
The navigation elements have been relocated to the top right corner of the site, and product displays have been removed Upon user login, the system presents a control item that manages user behavior, including store owners, administrators, and consumers While customer accounts possess only basic controls, more privileged accounts, such as those of store owners and administrators, have access to the system's inner workings.
We have introduced a new product page on our site, where certain items have been moved from the main page to enhance user experience This page allows clients to easily browse products related to the document they are viewing by swiping left or right or by searching for specific items Additionally, users can hover over a product to see a small preview, and clicking on it will reveal detailed product information.
We made several enhancements to the completed product, including adjustments to the pricing and description Additionally, we introduced an author section that appears after the description and before the category A new publisher component has also been added under the category section Lastly, we transformed the quantity display into a box format, allowing users to input their desired quantity directly.
The cart page has been enhanced with an up and down button for easy quantity updates, while unnecessary elements have been removed for a cleaner look Customers can now view the item's title, price, and quantity directly on the cart page The system automatically recalculates the total price based on the selected quantity, allowing customers to adjust their order seamlessly by pressing the increase or decrease button.
The user interface of the Mange account has been updated, with key information such as Username and Full Name now relocated from the left side to the top of the information box.
Screenshots of using GitHub or GitLab to manage the source code
The project's source code is hosted on GitHub
GitHub is an online platform that simplifies the process of publishing code and projects, offering storage for personal Git repositories It facilitates collaboration among team members and supports both its own features and the full range of Git functionalities.
GitHub can be viewed as a social networking platform for engineers to display their projects, which can range from website development to the implementation of operating systems like Linux or Android.
Then we used the command to clone the archive to the computer
After completing a function or changing the code, if you want to upload it to github, use the following commands Git add
Figure 45 Upload it to Github
Link Code : https://github.com/CVPhuc/FPTBook
Screenshots of using IIS or Azure for the application deployment
IIS is the application we choose to deploy for y the project
Internet Information Services (IIS) 7 and later provide a request-processing architecture which includes:
The Windows Process Activation Service (WAS), which enables sites to use protocols other than HTTP and HTTPS
A Web server engine that can be customized by adding or removing modules Integrated request-processing pipelines from IIS and ASP.NET
IIS, or Internet Information Services, comprises several key components that are essential for the application and web server roles in Windows Server® 2008 (IIS 7.0) and Windows Server 2008 R2 (IIS 7.5) These components are responsible for critical functions, including listening for server requests, managing processes, and reading configuration files Notable components include protocol listeners like HTTP.sys, as well as services such as the World Wide Web Publishing Service (WWW service) and the Windows Process Activation Service (WAS).
First, right-click on Sites and click Add Website to add a website
To File Publish, provide the site name and physical path Select the relevant IP address in Binding and click OK
Figure 49 Fill in the information on the website
Then, to view the just launched website, click the Browse Website option in the right sidebar
Figure 50 Go to the website
Application evaluation
Review the performance of the application
Users have made various modifications to their projects, resulting in more comprehensive products than initially planned The introduction of new features has enhanced project management, improving both convenience and user experience with a more user-friendly website interface.
No Use case Describe Mock-up Updated mock-up Result Complete
1 Log in Log i n page of t he website
2 Register Register page of t he website
3 Home Home page of t he website
4 Book Book page of t he website
Category page of t he website
The following table contrasts Initial Requirements before to change, following change, and following project completion:
Edit Category page of th e website
Delete Category page of th e website
Book (Owner) page of th e website
Create Book (Owner) page of th e website
Edit Book (Owner) page of th e website
Delete Book (Owner) page of th e website
Order (Owner) page of th e website
Request Category (Admin) page of t he website
Reject Request Category (Admin) page of t he website
Approval Request Category (Admin) page of t he website
Manage User (Admin) page of t he website
Manage Owner (Admin) page of t he website
Create Owner (Admin) page of t he website
Conclude whether the application adapts all requirements, or it needs to be improved later
The system maintains consistent operations, featuring login and logout capabilities, CRUD functions, and role management Admins can accept or reject shop owners' requests for new book catalogs Looking ahead, we aim to enhance user experience and introduce online payment options based on data from customers, company owners, and administrators.
Analyze the factors that influence the performance of the application
The software's functionality was evaluated across various scenarios to ensure effective data encryption and minimize user errors The developer addressed several issues to prevent unauthorized access to admin features, which are restricted based on user privileges outlined in the necessary documentation By dynamically displaying or hiding functionalities according to a user's role, the developer reduces the risk of users inadvertently accessing capabilities they are not permitted to use.
Evaluate the strengths and weaknesses of the application
The source code is easy to maintain, debug, and operate due to the MVC architectural pattern and the ASP.NET framework, which allow each module to function independently This functional modularization enhances organization and readability.
Cart (User) page of t he website
Manage Account (User) page of th e website
The flexibility of the code enhances error reduction and minimizes issues By utilizing independent components, application design, administration, operation, and maintenance become simpler Additionally, the MVC methodology establishes a standardized project model, facilitating easier access to the application.
To create an effective business application based on a specific Software Design Document, it is essential to implement tools, procedures, and techniques that ensure the system is fully operational Key features include CRUD functionality, role management, and a login/logout system, along with an admin feature that allows for the approval or disapproval of shop owners' requests for new book catalogs The application also supports data export to Excel and provides a chart detailing information about consumers, business owners, and administrators The code reflects the entities outlined in the class diagram, with each object incorporating the specified attributes and methods Furthermore, an image option has been added for business owners and administrators to enhance the application's realism.
Administrator duties must encompass the ability to manage lists by adding, editing, deleting, and viewing them, as outlined in the requirements specification The author's solution effectively incorporates these essential elements, demonstrating that the developer has successfully fulfilled the paper's criteria Whenever a user modifies the data—whether by adding, updating, or deleting—this information is promptly sent to the database system, ensuring that the data reflects the user's requests Additionally, all functions undergo thorough testing to guarantee their completeness, efficiency, and absence of errors.
Crawling data can be utilized to gather user information, primarily from publicly accessible online sources This method can yield a significant amount of personal details, such as phone numbers and email addresses.
In contrast, the system only encrypts passwords If a crawler sends the server a lot of requests in an effort to get data, the server might experience issues
Reputational damage can lead to significant long-term losses for e-commerce websites, especially for smaller online retailers that may face closure if clients and suppliers lose trust Therefore, having a robust data breach response plan is crucial to mitigate these risks.
When user numbers are high, setting restrictions becomes difficult for administrators, making pagination essential Pagination links multiple landing pages with related content, facilitating easier updates and improvements to the program's UI/UX.
+ Book page category-ordered: On our website, customers may immediately discover the book
The management application allows administrators to monitor users' login statuses, providing valuable insights into online versus offline access This feature can significantly enhance user management and facilitate quick improvements to the system Unfortunately, it remains unused due to the team's inability to finalize its development.
Administrators may sometimes upload incorrect or oversized images, which will trigger an error message to improve user experience Additionally, if a folder contains no images, relevant information will be displayed to inform users.
The development team faces significant challenges with their first project due to unfamiliarity, leading to frequent disputes over source code submissions and incompatible libraries and hardware A strategic shift was necessary when I uploaded the updated source code to GitHub, which coincided with our learning process on forking.
I have agreed to remove certain features temporarily, but we are committed to eventually reintegrating all functionalities into the system During this process, we discovered significant bugs that required extensive time to resolve, along with some features that, despite our initial plans, caused conflicts and unresolvable errors once implemented.
Available at: https://www.geeksforgeeks.org/introduction-to-visual-studio/ geeksforgeeks, 2023 geeksforgeeks [Online]
Available at: https://www.geeksforgeeks.org/html5-introduction/