iT邦幫忙

2022 iThome 鐵人賽

DAY 26
0
自我挑戰組

用 30 天和 ASP.NET Core 打造一個活動報名管理系統系列 第 26

ASP.NET Core - 活動報名管理系統:Day26 Repository、Controller 與 Services 加入活動報名與儲存報名資訊的功能

  • 分享至 

  • xImage
  •  

前言

關於活動報名以及身份驗證的流程,已經在昨天的文章中規劃好了,今天會著手將 Repository 與 Controller 儲存報名者資訊的功能實現出來。

Repository

EventsRepository

在昨天,我們將儲存報名者資訊,EventsEnroll 的 Model 與 Table 建立好,而 Repository 也要加入將資料存到 EventsEnroll 的 Function。

依據報名功能流程的規劃,Repository 會加入兩個功能:

  1. 在活動報名時,儲存使用者資訊到 EventsEnroll
    • 報名時,需判斷當下時間是否在活動開放報名時間的範圍內
  2. 取消活動報名時,刪除在 EventsEnroll 中的使用者資訊
  3. 取得該活動目前報名人數

SaveUserInfoToEventsEnrollAsync

(不太確定 Function Name 取這麼長是不是能被接受的QQ)

public async Task<bool> SaveUserInfoToEventsEnrollAsync(EventsEnroll eventsEnroll)
{
            _appDbContext.EventsEnroll.Add(eventsEnroll);
            var count = await _appDbContext.SaveChangesAsync();

            return count > 0;
}

DeleteUserInfoFromEventsEnrollAsync

public async Task<bool> DeleteUserInfoFromEventsEnrollAsync(EventsEnroll eventsEnroll)
{
            _appDbContext.EventsEnroll.Remove(eventsEnroll);
            var count = await _appDbContext.SaveChangesAsync();

            return count > 0;
}

GetApplicateQtyByEventIdAsync

public async Task<int> GetApplicateQtyByEventIdAsync(int eventId)
{
            var qty = await _appDbContext.EventsEnroll.Where(
                ee => ee.Events.Id == eventId
                ).CountAsync();

            return qty;
}

Services

EventsApplyServices

做一個 C# 版的 SQL Between 功能,判斷當下時間是否在傳入的 Events 的報名時間範圍內,以及判斷現在 EventsEnroll 的資料數量(EventId 為現在選擇的活動)是否與該活動人數上限相同:

    public class EventsApplyServices
    {
        private readonly IEventsRepository _eventsRepository;

        public EventsApplyServices(IEventsRepository eventsRepository)
        {
            _eventsRepository = eventsRepository;
        }

        public bool IsInEventsSalesTime(Events @event)
        {
            var salesTimeStart = @event.SaleTimeStart;
            var salesTimeEnd = @event.SaleTimeEnd;
            var dateTimeNow = DateTime.Now;

            if (salesTimeStart <= dateTimeNow && salesTimeEnd >= dateTimeNow )
                return true;

            return false;
        }

        public async Task<bool> IsApplicationLimitedQtyFull(Events @event)
        {
            var applicationLimitedQty = @event.EventsInfo.ApplicationLimitedQty;
            var eventsApplicationQty = await _eventsRepository.GetApplicateQtyByEventIdAsync(@event.Id);

            return applicationLimitedQty == eventsApplicationQty;
        }
    }

理論上 Services 應該要是 static,不過若要讓 static class 可以被 DI 注入服務,似乎有點麻煩(參考 Reference),所以我還是先用土法煉鋼的方式,等之後再慢慢改善系統。

Controller

建構子

為了取得當前登入使用者的資訊,Controller 的建構子加入 UserManager<ApplicationUser>,提供 DI 注入:

        private readonly AppDbContext _context;
        private readonly IWebHostEnvironment _env;
        private readonly IEventsRepository _eventsRepository;
        private readonly UserManager<ApplicationUser> _userManager;

        public EventsController(AppDbContext context, IEventsRepository eventsRepository,
            IWebHostEnvironment env,
            UserManager<ApplicationUser> userManager)
        {
            _context = context;
            _env = env;
            _eventsRepository = eventsRepository;
            _userManager = userManager;
        }

新增報名的 Action:

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> EventsEnroll(int? id)
        {
            Events Event = new Events();
            try
            {
                if (id != null)
                {
                    Event = await _eventsRepository.GetEventByIdAsync(id);
                    EventsApplyServices EventsApplyServices = new EventsApplyServices(_eventsRepository);
                    var isInEventsSalesTime = EventsApplyServices.IsInEventsSalesTime(Event);
                    var isApplicationLimitedQtyFull = await EventsApplyServices.IsApplicationLimitedQtyFull(Event);
                    var useId = User.FindFirstValue(ClaimTypes.NameIdentifier);

                    EventsEnroll EventsEnroll = new EventsEnroll()
                    {
                        Events = Event,
                        ApplicationUserId = useId
                    };

                    if (isInEventsSalesTime == true && isApplicationLimitedQtyFull == false)
                    {
                        await _eventsRepository.SaveUserInfoToEventsEnrollAsync(EventsEnroll);
                        TempData["Message"] = "報名成功";
                    }
                    else
                    {
                        TempData["Message"] = "報名失敗";
                    }
                }
                else
                {
                    return BadRequest();
                }
            }
            catch (Exception)
            {
                throw new Exception("報名失敗");
            }

            return RedirectToAction("Details", Event);
        }

View

Events/Details

在 HTML 的最前方加入 Form Tag 與 Id 欄位:

<form asp-action="EventsEnroll" method="post" style="display:inline;">
    <input type="hidden" asp-for="Id" />

最下方加入結束的 Form Tag 與 EventsEnroll 的 Submit Btn:

<input type="submit" value="報名" class="btn btn-primary" /> |
        <a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
        <a asp-action="Index">Back to List</a>
    </div>
</form>

Startup.cs

services.AddHttpContextAccessor();

本日結語

今天將加入了 UserManager,並且可以用來取 UserId, UserName 等資料,
也成功新增了報名儲存用戶資料的 Action。
明天將會完成取消報名以及在活動畫面顯示當前報名人數欄位。

那麼我們明天見!

Reference

[C#/Unity] 這不叫 Singleton,叫 Service Locator – Practice of Service Locator
[Architecture] Service Locator
How to get the current logged in user ID in ASP.NET Core?


上一篇
ASP.NET Core - 活動報名管理系統:Day25 活動舉辦與活動報名的流程規劃與 Table
下一篇
活動報名管理系統:Day27 完成取消活動報名、刪除報名資訊即無法報名的功能
系列文
用 30 天和 ASP.NET Core 打造一個活動報名管理系統30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言