0 Asp.Net Core 項目實戰之權限管理系統(0) 無中生有
1 Asp.Net Core 項目實戰之權限管理系統(1) 使用AdminLTE搭建前端
2 Asp.Net Core 項目實戰之權限管理系統(2) 功能及實體設計
3 Asp.Net Core 項目實戰之權限管理系統(3) 通過EntityFramework Core使用PostgreSQL
4 Asp.Net Core 項目實戰之權限管理系統(4) 依賴注入、倉儲、服務的多項目分層實現
5 Asp.Net Core 項目實戰之權限管理系統(5) 用戶登錄
6 Asp.Net Core 項目實戰之權限管理系統(6) 功能管理
7 Asp.Net Core 項目實戰之權限管理系統(7) 組織機構、角色、用戶權限
8 Asp.Net Core 項目實戰之權限管理系統(8) 功能菜單的動態加載
0 服務層實現
系統登錄后,會在session中記錄當前登錄用戶的信息。
//檢查用戶信息 var user = _userAppService.CheckUser(model.UserName, model.Password); if (user != null) { //記錄Session HttpContext.Session.SetString("CurrentUserId", user.Id.ToString()); HttpContext.Session.Set("CurrentUser", ByteConvertHelper.Object2Bytes(user)); //跳轉到系統首頁 return RedirectToAction("Index", "Home"); }
由於一個用戶可以擁有多個角色,我們需要做的是,根據當前登錄用戶的Id,得到其擁有的所有角色信息,然后取當前用戶所有角色擁有的功能權限求合集,得到的就是當前登錄用戶所擁有的功能權限信息。
定義應用服務接口
在IMenuAppService中定義接口
/// <summary> /// 根據用戶獲取功能菜單 /// </summary> /// <param name="userId">用戶ID</param> /// <returns></returns> List<MenuDto> GetMenusByUser(Guid userId);
服務接口實現
在MenuAppService中實現接口
/// <summary> /// 根據用戶獲取功能菜單 /// </summary> /// <param name="userId">用戶ID</param> /// <returns></returns> public List<MenuDto> GetMenusByUser(Guid userId) { List<MenuDto> result = new List<MenuDto>(); var allMenus = _menuRepository.GetAllList(it=>it.Type == 0).OrderBy(it => it.SerialNumber); if (userId == Guid.Empty) //超級管理員 return Mapper.Map<List<MenuDto>>(allMenus); var user = _userRepository.GetWithRoles(userId); if (user == null) return result; var userRoles = user.UserRoles; List<Guid> menuIds = new List<Guid>(); foreach (var role in userRoles) { menuIds = menuIds.Union(_roleRepository.GetAllMenuListByRole(role.RoleId)).ToList(); } allMenus = allMenus.Where(it => menuIds.Contains(it.Id)).OrderBy(it => it.SerialNumber); return Mapper.Map<List<MenuDto>>(allMenus); }
1 使用ViewComponent動態加載菜單
在以前的Asp.net MVC中,我們會經常使用@Html.Action來發起一個ChildAction請求,渲染並得到一個分部視圖填充的主功能視圖中,以此來實現一些公用的或者是獨立的界面區域。在Asp.Net Core中,不在存在將以ViewComponent替代。
你可以將View Component看做是一個mini的Controller——它只負責渲染一小部分內容,而非全部響應,所有分部視圖能解決的問題,你都可以使用View Component來解決,比如:動態導航菜單、Tag標簽、登錄窗口、購物車、最近閱讀文章等等。
1.0 ViewComponent創建
ViewComponent創建非常簡單,只需要將我們的類繼承自ViewComponent類就行了。每個ViewComponent需要包括一個名稱為Invoke的約定方法,你可以在此方法中傳入你需要的任何參數,系統也支持InvokeAsync方法實現異步功能,此約定方法為該ViewComponent的最終輸出出口。
在Fonour.MVC項目中新建一個名稱為“Components”的文件夾,用來存放我們所有的視圖組件類,在該文件夾下新建一個名稱為NavigationViewComponent的組件。
[ViewComponent(Name = "Navigation")] public class NavigationViewComponent : ViewComponent { private readonly IMenuAppService _menuAppService; private readonly IUserAppService _userAppService; public NavigationViewComponent(IMenuAppService menuAppService, IUserAppService userAppService) { _menuAppService = menuAppService; _userAppService = userAppService; } public IViewComponentResult Invoke() { var userId = HttpContext.Session.GetString("CurrentUserId"); var menus = _menuAppService.GetMenusByUser(Guid.Parse(userId)); return View(menus); } }
1.1 組件對應的視圖文件創建
上面實現的約定方法Invoke中,最后Return View(Menus),與我們控制器中Action返回視圖的方法很相似。ViewComponent尋找視圖也是遵照約定的。他會自動從以下路徑去尋找對應的視圖文件。
/Views/[CurrentController]/Components/[NameOfComponent]/Default.cshtml
/Views/Shared/Components/[NameOfComponent]/Default.cshtml
對於某個具體功能對應的組件,我們最好按照上面第一種路徑規則,把對應的視圖文件放在功能對應的Controller下面
對於系統級別的視圖組件,比如我們現在要實現的左側功能導航菜單,建議按照第二種路徑規則,放在Views/Shared下面。
在Views/Shared文件夾下新建一個名稱為Components的文件夾,然后在該文件夾下創建一個名稱為“Navigation”的文件夾,注意這個文件夾名與我們上面定義的組件名稱是要保持一直的。
在“Navigation”文件夾下創建一個名稱為Default.cshtml的視圖頁。內容如下:
@model List<Fonour.Application.MenuApp.Dtos.MenuDto> <li class="header">權限管理</li> @foreach (var menu in Model) { var isActive = ViewBag.CurrentMenu == menu.Code; //判斷當前功能是否處於激活 <li class="@(isActive ? "active" : "")"><a href="@menu.Url"><i class="fa fa-link"></i> <span>@menu.Name</span></a></li> }
該視圖接受一個在我們組件類中返回的菜單集合對象,並根據此菜單集合渲染我們需要的菜單。我們根據ViewBag.CurrentMenu是否等於當前菜單的編碼,來確定該菜單是否屬於激活狀態,這樣可以實現我們單擊某個菜單界面刷新后,該功能菜單處於激活狀態。
基於此,我們需要在每個功能頁面指定ViewBag.CurrentMenu的值。如用戶管理功能,我們在/Views/User/Index.cshtml頂部添加如下代碼即可。
@{
ViewBag.CurrentMenu = "User";
}
當然,如果你覺得這種硬編碼的方式你不喜歡,你可以在菜單單擊的時候,把當前菜單對應的code值傳至服務端,由服務端在返回對應的視圖之前,指定ViewBag.CurrentMenu的值即可。
1.2 ViewComponent的使用
我們修改布局頁_Layout.cshtml中菜單加載部分的代碼,將寫死的功能菜單信息,修改為通過使用ViewComponent根據用戶Id動態加載功能菜單。
<ul class="sidebar-menu"> @await Component.InvokeAsync("Navigation"); @*<li class="treeview"> <a href="#"> <i class="fa fa-link"></i> <span>Multilevel</span> <span class="pull-right-container"> <i class="fa fa-angle-left pull-right"></i> </span> </a> <ul class="treeview-menu"> <li><a href="#">Link in level 2</a></li> <li><a href="#">Link in level 2</a></li> </ul> </li>*@ </ul>
此時我們使用一個只分配了其中三個菜單權限的賬戶登錄系統,一切按照我們預想的,可以根據當前登錄用戶動態加載該用戶所擁有權限的功能菜單了,而且我們進入某個功能后,頁面刷新后已經可以自動把我們進入的功能菜單設置為激活狀態了。
2 總結
本次主要學習了ViewComponent的使用,實現了功能菜單的動態加載。
最開始是本着自己學習的態度寫這個系列的,內容總體來說屬於基礎入門級的,到現在也算是基本功能都已經實現了,里面有很多不足或不完善的地方,可以根據需要進行調整吧。
從孩子出生,轉眼間到現在3個月了,每天熬夜熬的精疲力盡,工作上也是忙的不可開交,有些朋友給我的留言中的,我有空看到就回復了,有些朋友的問題,有可能我沒時間看到,也有可能實在抽不出時間去幫你找問題所在,還得麻煩您自己多動手實踐一下了,請見諒。



