Asp.Net Core 項目實戰之權限管理系統(8) 功能菜單的動態加載

0 Asp.Net Core 項目實戰之權限管理系統(0) 無中生有html

1 Asp.Net Core 項目實戰之權限管理系統(1) 使用AdminLTE搭建前端前端

2 Asp.Net Core 項目實戰之權限管理系統(2) 功能及實體設計git

3 Asp.Net Core 項目實戰之權限管理系統(3) 經過EntityFramework Core使用PostgreSQLgithub

4 Asp.Net Core 項目實戰之權限管理系統(4) 依賴注入、倉儲、服務的多項目分層實現session

5 Asp.Net Core 項目實戰之權限管理系統(5) 用戶登陸app

6 Asp.Net Core 項目實戰之權限管理系統(6) 功能管理異步

7 Asp.Net Core 項目實戰之權限管理系統(7) 組織機構、角色、用戶權限ide

8 Asp.Net Core 項目實戰之權限管理系統(8) 功能菜單的動態加載佈局

github源碼地址學習

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」的文件夾,注意這個文件夾名與咱們上面定義的組件名稱是要保持一直的。

image

在「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>

此時咱們使用一個只分配了其中三個菜單權限的帳戶登陸系統,一切按照咱們預想的,能夠根據當前登陸用戶動態加載該用戶所擁有權限的功能菜單了,並且咱們進入某個功能後,頁面刷新後已經能夠自動把咱們進入的功能菜單設置爲激活狀態了。

image

image

2 總結

本次主要學習了ViewComponent的使用,實現了功能菜單的動態加載。

最開始是本着本身學習的態度寫這個系列的,內容整體來講屬於基礎入門級的,到如今也算是基本功能都已經實現了,裏面有不少不足或不完善的地方,能夠根據須要進行調整吧。

從孩子出生,轉眼間到如今3個月了,天天熬夜熬的精疲力盡,工做上也是忙的不可開交,有些朋友給個人留言中的,我有空看到就回復了,有些朋友的問題,有可能我沒時間看到,也有可能實在抽不出時間去幫你找問題所在,還得麻煩您本身多動手實踐一下了,請見諒。

相關文章
相關標籤/搜索