Trong bài viết này, chúng ta sẽ thêm một số thuộc tính cho Identity User và tạo trang Profile dùng để update thông tin cho user
Xem thêm:
- https://nhatkyhoctap.blogspot.com/2023/01/aspnet-identity-part-1.html
- https://nhatkyhoctap.blogspot.com/2023/01/aspnet-identity-part-2.html
- https://nhatkyhoctap.blogspot.com/2023/03/aspnet-identity-lam-quen-voi-role-trong.html
Custom Identity User
Mở file ApplicationUser.cs, thêm 2 thuộc tính DateOfBirth và ProfilePicture
Chúng ta định nghĩa Profile Picture kiểu byte[] dùng để lưu trữ image data. Nếu các bạn muốn lưu trữ bằng file vật lý trong thư mục wwwroot thì tham khảo thêm ở đây: ASP.NET Core: Upload file
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime? DateOfBirth { get; set; }
public byte[] ProfilePicture { get; set; }
}
Mở Package Manager Console, thực hiện tạo mới 1 migration
Add-Migration AddProfilePicture
Update-Database
Thêm trang Profile
Chúng ta sẽ có các step như sau- Thêm 2 action: Manage (get) và Manage (post) để quản lý việc hiển thị và update Identity User
- Thêm Model UserProfileViewModel chứa các properties dùng để hiển thị trên trang Profile
- Thêm option SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true để hệ thống không thêm thêm Required cho các property
public class UserProfileViewModel
{
[Display(Name = "First Name")]
[Required(ErrorMessage = "Your First Name is required")]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
[Required(ErrorMessage = "Your Last Name is required")]
public string LastName { get; set; }
[Display(Name = "User name")]
public string Username { get; set; }
[Display(Name = "Date Of Birth")]
[BindProperty, DataType(DataType.Date)]
public DateTime? DateOfBirth { get; set; }
[Phone]
[Display(Name = "Phone number")]
[Required]
public string PhoneNumber { get; set; }
[Display(Name = "Profile Picture")]
public byte[] ProfilePicture { get; set; }
}
Mở file AccountController, thêm đoạn code như sau:
public async Task<IActionResult> Manage()
{
var username = _userManager.GetUserName(User);
if(string.IsNullOrEmpty(username))
{
return RedirectToAction("Login", "Account");
}
var user = await _userManager.FindByNameAsync(username);
if (user == null)
{
return RedirectToAction("Login", "Account");
}
var userProfile = new UserProfileViewModel
{
PhoneNumber = user.PhoneNumber??string.Empty,
Username = user.UserName ?? string.Empty,
FirstName = user.FirstName,
LastName = user.LastName,
DateOfBirth = user.DateOfBirth,
ProfilePicture = user.ProfilePicture
};
return View(userProfile);
}
[HttpPost]
public async Task<IActionResult> Manage(UserProfileViewModel model, IFormFile ProfilePicture)
{
if(!ModelState.IsValid)
{
model.Username = User.Identity.Name;
return View(model);
}
var username = User.Identity?.Name;
if (string.IsNullOrEmpty(username))
{
return RedirectToAction("Login", "Account");
}
var user = await _userManager.FindByNameAsync(username);
if (user == null)
{
return RedirectToAction("Login", "Account");
}
user.FirstName = model.FirstName;
user.LastName = model.LastName;
user.PhoneNumber = model.PhoneNumber;
user.DateOfBirth = model.DateOfBirth;
if(ProfilePicture != null)
{
using (var dataStream = new MemoryStream())
{
await ProfilePicture.CopyToAsync(dataStream);
user.ProfilePicture = dataStream.ToArray();
}
}
await _userManager.UpdateAsync(user);
model.ProfilePicture = user.ProfilePicture;
model.Username = username;
return View(model);
}
Thêm View cho action Manage:
@model UserProfileViewModel
<form id="profile-form" method="post" enctype="multipart/form-data">
@Html.ValidationSummary(true)
<div class="row">
<div class="col-md-6">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group mb-3">
<label asp-for="FirstName"></label>
<input asp-for="FirstName" class="form-control" />
<span asp-validation-for="FirstName" class="text-danger"></span>
</div>
<div class="form-group mb-3">
<label asp-for="LastName"></label>
<input asp-for="LastName" class="form-control" />
<span asp-validation-for="LastName" class="text-danger"></span>
</div>
<div class="form-group mb-3">
<label asp-for="Username"></label>
<input asp-for="Username" class="form-control" disabled />
<span asp-validation-for="Username" class="text-danger"></span>
</div>
<div class="form-group mb-3">
<label asp-for="DateOfBirth"></label>
<input asp-for="DateOfBirth" class="form-control" max="@DateTime.Now.ToString("yyyy-MM-ddThh:mm")" min="@DateTime.Now.AddYears(-100).ToString("yyyy-MM-ddThh:mm")" />
<span asp-validation-for="DateOfBirth" class="text-danger"></span>
</div>
<div class="form-group mb-3">
<label asp-for="PhoneNumber"></label>
<input asp-for="PhoneNumber" class="form-control" />
<span asp-validation-for="PhoneNumber" class="text-danger"></span>
</div>
<button id="update-profile-button" type="submit" class="btn btn-primary">Save</button>
</div>
<div class="col-md-6">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group mb-3">
<label asp-for="ProfilePicture" style="width: 100%;"></label>
@if (Model.ProfilePicture != null && Model.ProfilePicture.Length > 0)
{
<img id="profilePicture" style="width:275px;height:275px; object-fit:cover" src="data:image/*;base64,@(Convert.ToBase64String(Model.ProfilePicture))">
}
else
{
<img id="profilePicture" style="width:275px;height:275px; object-fit:cover" src="~/images/default_avatar-png.png">
}
</div>
<div class="form-group mb-3">
<input type="file" class="form-control"
accept=".png,.jpg,.jpeg,.gif,.tif"
asp-for="ProfilePicture"
onchange="document.getElementById('profilePicture').src = window.URL.createObjectURL(this.files[0])" />
<span asp-validation-for="ProfilePicture" class="text-danger"></span>
</div>
</div>
</div>
</form>
Set SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true trong Program.cs để hệ thống không thêm attribute Required các các thuộc tính non-null trên View
// Add services to the container.
builder.Services.AddControllersWithViews(options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true);
var app = builder.Build();
Nguyên nhân:
The validation system in .NET Core 3.0 and later treats non-nullable parameters or bound properties as if they had a [Required] attribute.
Build và run application để kiểm tra thành quả.
Download source code: https://github.com/anbinhtrong/AuthenticationAndAuthorization/releases/tag/profile_page_v4.0
Tham khảo
https://codewithmukesh.com/blog/user-management-in-aspnet-core-mvc/#Adding_a_Profile_Picture
Chúc các bạn thành công!
Nhận xét
Đăng nhận xét