abp web.mvc項目中的菜單加載機制
- 2020 年 5 月 12 日
- 筆記
- abp, Asp.Net Core
abp中的菜單加載機制
在abp中菜單的定義與我們傳統寫的框架不一樣,它是在編寫代碼的時候配置,而我們一般寫的通用權限管理系統中,是後期在後台界面中添加的。這一點有很大不同。abp關於菜單的定義及管理挺複雜的。
與菜單相關的結構類、接口及擴展方法類
- MenuDefinition:定義應用程序的菜單的結構
- MenuItemDefinition:定義應用程序的菜單項的結構
- IHasMenuItemDefinitions: 定義子菜單的接口
- HasMenuItemDefinitionsExtensions:查詢子菜單項的擴展方法類
- MenuItemDefinitionExtensions:操作菜單項的擴展方法類
- UserMenu:單個用戶的菜單結構
- UserMenuItem:單個用戶的菜單中的菜單項
與菜單相關的操作類
這裡分為兩類,一類是針對應用系統的菜單:
- NavigationProvider:提供設置應用系統導航菜單及菜單項的方法SetNavigation
- INavigationProviderContext:Provider模式的上下文接口
- NavigationProviderContext:Provider模式的上下文類,設置NavigationManager
- INavigationManager:導航菜單管理應用服務接口
- NavigationManager:導航菜單管理應用服務類,包括構造默認主菜單,初始化菜單的所有菜單項方法。
另一類是針對用戶菜單的操作: - IUserNavigationManager: 用戶菜單管理應用服務接口
- UserNavigationManager:用戶菜單管理應用服務類,提供了獲取指定用戶的菜單, 根據用戶權限填充菜單項方法。
上面的所有類及接口都是在Abp這個項目中定義的。
Web.MVC中的菜單應用
菜單的定義
菜單定義在ContosoAbp.Web.Startup命名空間下的ContosoAbpNavigationProvider類中,這裡ContosoAbp為自定義的項目名。ContosoAbpNavigationProvide繼承自NavigationProvider抽象類,是實際菜單的定義者。這裡利用了Provider模式,微軟經常用這種模式。
using Abp.Application.Navigation;
using Abp.Authorization;
using Abp.Localization;
using ContosoAbp.Authorization;
namespace ContosoAbp.Web.Startup
{
/// <summary>
/// This class defines menus for the application.
/// 定義應用程序的菜單
/// </summary>
public class ContosoAbpNavigationProvider : NavigationProvider
{
public override void SetNavigation(INavigationProviderContext context)
{
context.Manager.MainMenu
.AddItem(
new MenuItemDefinition( //首頁
PageNames.Home,
L("HomePage"),
url: "",
icon: "fas fa-home",
requiresAuthentication: true,
order:0
)
).AddItem(
new MenuItemDefinition( //空頁面
PageNames.Empty,
L("EmptyPage"),
url: "Home/Empty",
icon: "fas fa-home",
requiresAuthentication: false,
order: 1
)
).AddItem(
new MenuItemDefinition( //附件
PageNames.Attachment,
L("Attachment"),
url: "Attachment",
icon: "fas fa-home",
requiresAuthentication: false,
order: 2
)
).AddItem(
new MenuItemDefinition( //租戶
PageNames.Tenants,
L("Tenants"),
url: "Tenants",
icon: "fas fa-building",
permissionDependency: new SimplePermissionDependency(PermissionNames.Pages_Tenants),
order: 3
)
).AddItem(
new MenuItemDefinition( // 用戶
PageNames.Users,
L("Users"),
url: "Users",
icon: "fas fa-users",
permissionDependency: new SimplePermissionDependency(PermissionNames.Pages_Users),
order: 4
)
).AddItem(
new MenuItemDefinition( //角色
PageNames.Roles,
L("Roles"),
url: "Roles",
icon: "fas fa-theater-masks",
permissionDependency: new SimplePermissionDependency(PermissionNames.Pages_Roles),
order: 5
)
)
.AddItem(
new MenuItemDefinition( //關於
PageNames.About,
L("About"),
url: "About",
icon: "fas fa-info-circle",
order: 6
)
).AddItem( // Menu items below is just for demonstration!
new MenuItemDefinition( //多級菜單
"MultiLevelMenu",
L("MultiLevelMenu"),
icon: "fas fa-circle",
order: 7
).AddItem(
new MenuItemDefinition(
"AspNetBoilerplate",
new FixedLocalizableString("ASP.NET Boilerplate"),
icon: "far fa-circle"
).AddItem(
new MenuItemDefinition(
"AspNetBoilerplateHome",
new FixedLocalizableString("Home"),
url: "//aspnetboilerplate.com?ref=abptmpl",
icon: "far fa-dot-circle"
)
).AddItem(
new MenuItemDefinition(
"AspNetBoilerplateTemplates",
new FixedLocalizableString("Templates"),
url: "//aspnetboilerplate.com/Templates?ref=abptmpl",
icon: "far fa-dot-circle"
)
).AddItem(
new MenuItemDefinition(
"AspNetBoilerplateSamples",
new FixedLocalizableString("Samples"),
url: "//aspnetboilerplate.com/Samples?ref=abptmpl",
icon: "far fa-dot-circle"
)
).AddItem(
new MenuItemDefinition(
"AspNetBoilerplateDocuments",
new FixedLocalizableString("Documents"),
url: "//aspnetboilerplate.com/Pages/Documents?ref=abptmpl",
icon: "far fa-dot-circle"
)
)
).AddItem(
new MenuItemDefinition(
"AspNetZero",
new FixedLocalizableString("ASP.NET Zero"),
icon: "far fa-circle"
).AddItem(
new MenuItemDefinition(
"AspNetZeroHome",
new FixedLocalizableString("Home"),
url: "//aspnetzero.com?ref=abptmpl",
icon: "far fa-dot-circle"
)
).AddItem(
new MenuItemDefinition(
"AspNetZeroFeatures",
new FixedLocalizableString("Features"),
url: "//aspnetzero.com/Features?ref=abptmpl",
icon: "far fa-dot-circle"
)
).AddItem(
new MenuItemDefinition(
"AspNetZeroPricing",
new FixedLocalizableString("Pricing"),
url: "//aspnetzero.com/Pricing?ref=abptmpl#pricing",
icon: "far fa-dot-circle"
)
).AddItem(
new MenuItemDefinition(
"AspNetZeroFaq",
new FixedLocalizableString("Faq"),
url: "//aspnetzero.com/Faq?ref=abptmpl",
icon: "far fa-dot-circle"
)
).AddItem(
new MenuItemDefinition(
"AspNetZeroDocuments",
new FixedLocalizableString("Documents"),
url: "//aspnetzero.com/Documents?ref=abptmpl",
icon: "far fa-dot-circle"
)
)
)
);
}
private static ILocalizableString L(string name)
{
return new LocalizableString(name, ContosoAbpConsts.LocalizationSourceName);
}
}
}
菜單的加載
菜單的加載是利用的視圖組件,定義了一個SideBarMenuViewComponent的視圖組件,在這個SideBarMenuViewComponent類中,利用IUserNavigationManager獲取用戶的菜單,返回SideBarMenuViewModel給前端,前端遍歷輸出菜單及子項。
後端視圖組件的定義
using System.Threading.Tasks;
using Abp.Application.Navigation;
using Abp.Runtime.Session;
using Microsoft.AspNetCore.Mvc;
namespace ContosoAbp.Web.Views.Shared.Components.SideBarMenu
{
/// <summary>
/// 側邊欄視圖組件
/// </summary>
public class SideBarMenuViewComponent : ContosoAbpViewComponent
{
/// <summary>
/// 側邊欄用戶導航管理
/// </summary>
private readonly IUserNavigationManager _userNavigationManager;
/// <summary>
/// Session服務
/// </summary>
private readonly IAbpSession _abpSession;
/// <summary>
/// 構造函數
/// </summary>
/// <param name="userNavigationManager"></param>
/// <param name="abpSession"></param>
public SideBarMenuViewComponent(
IUserNavigationManager userNavigationManager,
IAbpSession abpSession)
{
_userNavigationManager = userNavigationManager;
_abpSession = abpSession;
}
public async Task<IViewComponentResult> InvokeAsync()
{
var model = new SideBarMenuViewModel
{
MainMenu = await _userNavigationManager.GetMenuAsync("MainMenu", _abpSession.ToUserIdentifier())
};
return View(model);
}
}
}
前端遍歷輸出菜單
@using ContosoAbp.Web.Views.Shared.Components.SideBarMenu
@model SideBarMenuViewModel
@{
var orderedMenuItems = Model.MainMenu.Items.Where(x => x.IsVisible).OrderByCustom().ToList();
}
<nav class="mt-2">
<ul class="nav nav-pills nav-sidebar flex-column nav-flat" data-widget="treeview" role="menu" data-accordion="false">
@{
foreach (var item in orderedMenuItems)
{
@await Html.PartialAsync("Components/SideBarMenu/_MenuItem", item)
}
}
</ul>
</nav>