.Net core 2.0 利用Attribute获取MVC Action来生成菜单
最近在学习.net core的同时将老师的MVC5项目中的模块搬过来用,其中有一块就是利用Attribute来生成菜单。
一·首先定义Action实体
/// <summary> /// Action /// </summary> public class Action { /// <summary> /// ActionId /// </summary> [DisplayName("ActionId")] public Guid Id { get; set; } /// <summary> /// 唯一的名称 /// </summary> [DisplayName("唯一的名称")] public string Name { get; set; } /// <summary> /// 分区 /// </summary> [DisplayName("分区")] public string AreaName { get; set; } /// <summary> /// 控制器 /// </summary> [DisplayName("控制器")] public string ControllerName { get; set; } /// <summary> /// 活动 /// </summary> [DisplayName("活动")] public string ActionName { get; set; } /// <summary> /// 参数 /// </summary> [DisplayName("参数")] public string Parameter { get; set; } /// <summary> /// 文字 /// </summary> [DisplayName("文字")] public string Text { get; set; } /// <summary> /// 叶节点 /// </summary> [DisplayName("叶节点")] public bool IsLeaf { get; set; } /// <summary> /// 显示顺序 /// </summary> [DisplayName("显示顺序")] public int Ordinal { get; set; } /// <summary> /// 是否显示在左侧的导航栏中 /// </summary> [DisplayName("是否显示在左侧的导航栏中")] public bool ShowInLeftNavigationBar { get; set; } /// <summary> /// 图标 /// </summary> [DisplayName("图标")] public string IconClass { get; set; } /// <summary> /// 级次 /// </summary> [DisplayName("级次")] public int Depth { get; set; } /// <summary> /// 是否链接 /// </summary> [DisplayName("是否链接")] public bool IsLink { get; set; } /// <summary> /// 上级名称(采用上级名称而非上级Id是为了方便数据的存入) /// </summary> [DisplayName("上级名称")] public string ParentName { get; set; } /// <summary> /// 限制角色 /// </summary> [DisplayName("限制角色")] public string AllowedRoles { get; set; } }
二.新建Attribute类
/// <summary> /// 方法描述 /// </summary> [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] public class ActionDescriptorAttribute : Attribute {/// <summary> /// 方法描述 /// </summary> /// <param name="name">名称(必须唯一)</param> /// <param name="text">标题</param> /// <param name="depth">深度</param> /// <param name="ordinal">显示顺序</param> /// <param name="isLink">是否显示为链接</param> /// <param name="showInLeftNavigationBar">是否显示在左侧的导航栏中</param> public ActionDescriptorAttribute(string name, string text, bool isLink, int depth) { this.Name = name; this.Text = text; this.IsLink = isLink; this.Depth = depth; this.IsLeaf = true; this.ShowInLeftNavigationBar = true; this.Ordinal = 0; } /// <summary> /// 名称(必须唯一) /// </summary> public string Name { get; set; } /// <summary> /// 显示的文本 /// </summary> public string Text { get; set; } /// <summary> /// 图标 /// </summary> public string IconClass { get; set; } /// <summary> /// 参数 /// </summary> public string Parameter { get; set; } /// <summary> /// 是否子菜单 /// </summary> public bool IsLeaf { get; set; } /// <summary> /// 显示顺序 /// </summary> public int Ordinal { get; set; } /// <summary> /// 是否在左边导航栏显示 /// </summary> public bool ShowInLeftNavigationBar { get; set; } /// <summary> /// 一级菜单,该值为1,二级菜单,该值为2,依次类推 /// </summary> public int Depth { get; set; } /// <summary> /// 是否链接 /// </summary> public bool IsLink { get; set; } /// <summary> /// 上级名称 /// </summary> public string ParentName { get; set; } }
三.新建ActionsConfig类
public class ActionsConfig { /// <summary> /// 是否生成Actions /// </summary> public static bool GenerateConfigs { get; set; } /// <summary> /// 是否采用追加模式,如果是追加模式则不删除现有数据 /// </summary> public static bool IsAppendMode { get; set; } /// <summary> /// 是否更新现有记录 /// </summary> public static bool IsModifed { get; set; } public static Task<int> GetActions(string[] namespaces) { if (!GenerateConfigs) return new Task<int>(() => 0); DAL.NoteBookContext db = new DAL.NoteBookContext(); var types = Assembly.GetExecutingAssembly().GetExportedTypes().Where(t => namespaces.Contains(t.Namespace)).ToArray(); var actions = new List<DAL.Entities.Action>(); for (int i = 0; i < types.Length; i++) { bool isMvcController = types[i].IsSubclassOf(typeof(Controller)); //bool isApiController = types[i].IsSubclassOf(typeof(ApiController)); //if (!isMvcController && !isApiController) continue; var fullName = types[i].FullName; var name = types[i].Name; var areaName = GetAreaName(fullName); var tAttr = types[i].GetCustomAttribute<Attributes.ActionDescriptorAttribute>(); var authorize = types[i].GetCustomAttributes<AuthorizeAttribute>(); string roles = ""; if (authorize != null) roles = string.Join(",", authorize.Select(a => a.Roles)); if (null != tAttr) { string attrName = tAttr.Name; //如果是追加模式需要判断是否已经存在 bool find = db.Actions.Where(a => a.Name == attrName).Count() > 0; if (!IsAppendMode || !find) actions.Add(new DAL.Entities.Action { Id = Guid.NewGuid(), Name = tAttr.Name, Text = tAttr.Text, Parameter = tAttr.Parameter, AreaName = areaName, ControllerName = name.Substring(0, name.IndexOf("Controller")), ActionName = "#", IsLeaf = tAttr.IsLeaf, IconClass = tAttr.IconClass, Ordinal = tAttr.Ordinal, ShowInLeftNavigationBar = true, Depth = tAttr.Depth, ParentName = tAttr.ParentName, IsLink = tAttr.IsLink, AllowedRoles = roles }); if (find && IsModifed) { DAL.Entities.Action action = db.Actions.Where(a => a.Name == attrName).FirstOrDefault(); action.Text = tAttr.Text; action.Parameter = tAttr.Parameter; action.AreaName = areaName; action.ControllerName = name.Substring(0, name.IndexOf("Controller")); action.ActionName = "#"; action.IsLeaf = tAttr.IsLeaf; action.IconClass = tAttr.IconClass; action.Ordinal = tAttr.Ordinal; action.ShowInLeftNavigationBar = true; action.Depth = tAttr.Depth; action.ParentName = tAttr.ParentName; action.IsLink = tAttr.IsLink; action.AllowedRoles = string.IsNullOrEmpty(roles) || roles == "None" ? null : roles; if (string.IsNullOrEmpty(roles) || roles == "None") action.AllowedRoles = null; db.SaveChanges(); } } var methods = types[i].GetMethods(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance); for (int j = 0; j < methods.Length; j++) { var mAttr = methods[j].GetCustomAttribute<Attributes.ActionDescriptorAttribute>(); if (null != mAttr) { string attrName = mAttr.Name; //如果是追加模式需要判断是否已经存在 bool find = db.Actions.Where(a => a.Name == attrName).Count() > 0; if (find && IsModifed) { DAL.Entities.Action action = db.Actions.Where(a => a.Name == attrName).FirstOrDefault(); action.Text = mAttr.Text; action.Parameter = mAttr.Parameter; action.AreaName = areaName; action.ControllerName = name.Substring(0, name.IndexOf("Controller")); action.ActionName = methods[j].Name; action.IsLeaf = mAttr.IsLeaf; action.IconClass = mAttr.IconClass; action.Ordinal = mAttr.Ordinal; action.ShowInLeftNavigationBar = mAttr.ShowInLeftNavigationBar; action.Depth = mAttr.Depth; action.ParentName = mAttr.ParentName; action.IsLink = mAttr.IsLink; action.AllowedRoles = string.IsNullOrEmpty(roles) || roles == "None" ? null : roles; if (string.IsNullOrEmpty(roles) || roles == "None") action.AllowedRoles = null; db.SaveChanges(); } if (find && IsAppendMode) continue; actions.Add(new DAL.Entities.Action { Id = Guid.NewGuid(), Name = mAttr.Name, Text = mAttr.Text, Parameter = mAttr.Parameter, AreaName = areaName, ControllerName = name.Substring(0, name.IndexOf("Controller")), ActionName = methods[j].Name, IsLeaf = mAttr.IsLeaf, IconClass = mAttr.IconClass, Ordinal = mAttr.Ordinal, ShowInLeftNavigationBar = mAttr.ShowInLeftNavigationBar, Depth = mAttr.Depth, ParentName = mAttr.ParentName, IsLink = mAttr.IsLink, AllowedRoles = roles }); } } } var bll = new NoteBookBLL<DAL.Entities.Action>(); if (IsAppendMode) return bll.AddRangeAsync(actions); else return bll.DeleteAsync(a => true).ContinueWith(task => { return bll.AddRangeAsync(actions).Result; }); } private static string GetAreaName(string fullName) { string[] nameSections = fullName.Split(new char[] { '.' }); var areaIndex = Array.IndexOf(nameSections, "Areas", 0); string areaName = null; if (areaIndex > 0) areaName = nameSections[areaIndex + 1]; return areaName; } }
四.在StartUp中调用,项目启动时执行方法。
public Startup(IConfiguration configuration) { Configuration = configuration; ActionsConfig.GenerateConfigs = true; //是否采用追加模式 ActionsConfig.IsAppendMode = true; //是否修改现有记录 ActionsConfig.IsModifed = true; ActionsConfig.GetActions(new string[] { "xxx.Controllers"}); }
五.应用。只需在控制器上添加Attribute属性,就可以把相应的控制器加入到Action表中。
结果如图
萌新菜鸟,水平有限,此代码借鉴了我的老师的项目中的代码。欢迎各位大佬,批评指正,不吝赐教。
QQ:1051599574
邮箱:zhangjunx6497@163.com
欢迎交流讨论
QQ 1051599574