The Profile GET action is the engine that retrieves a customer's personal details from the database and displays them in a professional, editable dashboard. This step is critical for any ASP.NET Core MVC application that requires user account management.
Step-by-Step Code Explanation
Session Security Check: The code first looks for a
UserIdin the HttpContext.Session. If no ID is found, it means the user isn't logged in, so it securely redirects them to the Login page.Database Retrieval: Using
_context.Users.Find(userId), the system queries your SQL database to find the specific record matching the logged-in user. If the user doesn't exist in the database, it returns aNotFound()error.ViewModel Mapping: We don't pass the database "User" model directly to the view for security reasons. Instead, we map the data to a ProfileViewModel. This object carries the
Username,Email,FullName,Address, andPhoneto the frontend.View Delivery: Finally, the populated
modelis sent to theProfile.cshtmlview, where we will build our two-column layout: the update form on the left and the user status card (with "My Orders" and "Change Password" buttons) on the right.
[HttpGet]
public IActionResult Profile()
{
var userId = HttpContext.Session.GetInt32("UserId");
if (userId == null) return RedirectToAction("Login");
var user = _context.Users.Find(userId);
if (user == null) return NotFound();
var model = new ProfileViewModel
{
Id = user.Id,
Username = user.Username,
Email = user.Email,
FullName = user.FullName,
Address = user.Address,
Phone = user.Phone
};
return View(model);
}
The ProfileViewModel is a critical component because it acts as the data carrier between your SQL database and the user interface. By using a ViewModel instead of your raw database entity, you ensure that your application remains secure and follows the MVC Best Practices.
Step-by-Step Code Explanation
public int Id { get; set; }: This property stores the unique primary key of the user. We need this "hidden" ID so that when the user clicks "Save," the database knows exactly which record to update.[Display(Name = "Username")]: This attribute tells ASP.NET Core exactly what label to show in the UI. It makes your code cleaner by separating the variable name from the front-facing text.[Required]and[EmailAddress]: These are Data Annotations. They provide instant server-side validation. The[Required]tag ensures the email field isn't empty, and[EmailAddress]verifies the string follows the correct format (e.g., name@domain.com).Customer Details: Properties like
FullName,Address, andPhoneallow the user to manage their delivery information. Since these are in the ViewModel, they can be easily mapped to the input fields in our Bootstrap form.
using System.ComponentModel.DataAnnotations;
namespace FoodOrderingSystem.Models.ViewModels
{
public class ProfileViewModel
{
public int Id { get; set; }
[Display(Name = "Username")]
public string Username { get; set; }
[Required]
[EmailAddress]
public string Email { get; set; }
public string FullName { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
}
}
This view is a perfect example of modern UI design, combining a clean sidebar for status and navigation with a robust form for account updates. It’s designed to give your food ordering app a high-end, personalized feel.
Step-by-Step Code Explanation
Two-Column Layout: We use the Bootstrap grid system (
col-md-4andcol-md-8). The left side acts as a User Summary Card and navigation hub, while the right side is the Data Management area.User Status Sidebar: This section displays the user's name, username, and an "Active Member" badge. It also includes a
list-groupwith quick-access links to My Orders and Change Password, improving site navigation.Dynamic Feedback (TempData): The code includes alerts for
SuccessandErrormessages. When a user saves their changes, they get instant visual confirmation—crucial for a good user experience (UX).Security Measures:
Hidden Fields:
IdandUsernameare passed as hidden inputs to ensure the backend knows which record to update.Disabled Username: The username field is marked as
disabledbecause, in most professional systems, the unique login ID remains permanent for security.
Bootstrap Icons: We’ve integrated BI Icons (like
bi-person-circleandbi-save) to make the interface modern and intuitive for the customer.
@model FoodOrderingSystem.Models.ViewModels.ProfileViewModel
@{
ViewData["Title"] = "My Profile";
}
<div class="container my-5">
<div class="row">
<div class="col-md-4">
<div class="card shadow mb-4">
<div class="card-body text-center">
<div class="mb-3">
<i class="bi bi-person-circle display-1 text-primary"></i>
</div>
<h4>@Model.FullName</h4>
<p class="text-muted">@Model.Username</p>
<span class="badge bg-success">Active Member</span>
</div>
</div>
</div>
<div class="col-md-8">
<div class="card shadow">
<div class="card-header bg-primary text-white">
<h5 class="mb-0"><i class="bi bi-pencil-square"></i> Edit Profile</h5>
</div>
<div class="card-body">
@if (TempData["Success"] != null)
{
<div class="alert alert-success alert-dismissible fade show" role="alert">
@TempData["Success"]
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
}
@if (TempData["Error"] != null)
{
<div class="alert alert-danger alert-dismissible fade show" role="alert">
@TempData["Error"]
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
}
<form asp-action="Profile" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Id" />
<input type="hidden" asp-for="Username" />
<div class="mb-3">
<label class="form-label">Username</label>
<input asp-for="Username" class="form-control" disabled />
<small class="text-muted">Username cannot be changed</small>
</div>
<div class="mb-3">
<label asp-for="FullName" class="form-label"></label>
<input asp-for="FullName" class="form-control" />
<span asp-validation-for="FullName" class="text-danger"></span>
</div>
<div class="mb-3">
<label asp-for="Email" class="form-label"></label>
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="mb-3">
<label asp-for="Phone" class="form-label"></label>
<input asp-for="Phone" class="form-control" />
<span asp-validation-for="Phone" class="text-danger"></span>
</div>
<div class="mb-3">
<label asp-for="Address" class="form-label"></label>
<textarea asp-for="Address" class="form-control" rows="3"></textarea>
<span asp-validation-for="Address" class="text-danger"></span>
</div>
<div class="d-flex justify-content-between">
<button type="submit" class="btn btn-primary">
<i class="bi bi-save"></i> Save Changes
</button>
<button type="button" class="btn btn-outline-danger">
<i class="bi bi-trash"></i> Delete Account
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
This method is the "worker" that takes the updated information from the user's form, validates it for security and uniqueness, and commits those changes to your SQL database.
Step-by-Step Code Explanation
Session & Security: The code first verifies that a
UserIdexists in the session. This prevents unauthorized "anonymous" updates to user data.ModelState.IsValid: Before touching the database, the system checks if the data matches the rules we set in our ProfileViewModel (like valid email formats and required fields).Unique Email Validation: This is a critical professional step. The line
_context.Users.Any(...)checks if the new email address is already being used by another user. This prevents two accounts from sharing the same email.Database Update: We find the existing user record using the ID from the session and map the new values (
FullName,Email,Phone,Address) onto the database object._context.SaveChanges(): This executes the actual SQLUPDATEcommand.User Feedback (TempData): After a successful save, we store a message in
TempData["Success"]. Because we useRedirectToAction, this message will "survive" the redirect and appear on the refreshed profile page to notify the user of their success.
[HttpPost]
public IActionResult Profile(ProfileViewModel model)
{
var userId = HttpContext.Session.GetInt32("UserId");
if (userId == null) return RedirectToAction("Login");
if (ModelState.IsValid)
{
var user = _context.Users.Find(userId);
if (user == null) return NotFound();
// Check if email is already taken by another user
var emailExists = _context.Users.Any(u => u.Email == model.Email && u.Id != userId);
if (emailExists)
{
ModelState.AddModelError("Email", "Email is already registered to another account.");
return View(model);
}
user.FullName = model.FullName;
user.Email = model.Email;
user.Phone = model.Phone;
user.Address = model.Address;
_context.SaveChanges();
TempData["Success"] = "Profile updated successfully!";
return RedirectToAction("Profile");
}
return View(model);
}

Comments
Post a Comment