问题描述
我想动态生成导航菜单,该菜单遵循具有特定操作和控制器的应用程序的默认路由。 我在MVC5中找到了答案,但是我不知道如何在.Net Core MVC应用程序中做到这一点。
我在MVC5中尝试过的操作如下:
查看模型:
public class Menuviewmodel
{
// other props
public string Link
{
get
{
UrlHelper url = new UrlHelper(HttpContext.Current.Request.RequestContext);
return url.Action(this.Action != null ? this.Action : "StaticPage",this.Controller != null ? this.Controller : "StaticPage",new { pageName = this.PageTitle });
}
}
}
Global.asax:
public static List<Menuviewmodel> SetMenuHeads()
{
return
General.DataModel.Menus
.Where(m => m.IsHead)
.Select(Menuviewmodel.Set)
.ToList();
}
General.cs:
public static string SubMenuGenerator(Menuviewmodel menu)
{
string subMenus = "";
var subMenusList =
DataModel.Menus
.Where(m => m.ParentId == menu.ID)
.Select(Menuviewmodel.Set)
.ToList();
if (subMenusList.Count == 0)
subMenus += "<li><a href=\"" + menu.Link + "\" class=\"external\"><span>" + menu.RenderTitle + "</span></a></li>";
else
{
subMenus += "<li><a href=\"#\" class=\"external\"><span>" + menu.Title + "</span></a>";
subMenus += "<ul>";
foreach (var mnu in subMenusList)
{
subMenus += SubMenuGenerator(mnu);
}
subMenus += "</ul>";
subMenus += "</li>";
}
return subMenus;
}
_Layout.cshtml:
<nav id="main-nav">
<ul id="main-menu" class="sm-clean">
<li><a href="@Url.Action("Index","Home")" class="external"><span>Home</span></a></li>
@{
string menu = "";
foreach (var menuItem in global_asax.SetMenuHeads())
{
menu += General.SubMenuGenerator(menuItem);
}
}
@Html.Raw(menu)
</ul>
</nav>
现在我想尝试在.net核心中做同样的事情,但是.net核心中没有像HttpContext.Current.Request.RequestContext这样的类,它可以使用其动作和控制器来生成url。
有什么主意吗?
解决方法
在核心中,您可以通过 IActionDescriptorCollectionProvider 获取所有路径。
如果要将所有路由都放入导航栏中,则需要向核心项目的startup
添加自定义中间件,以将相应的html传递给{{ 1}}页。
这是完整的示例:
自定义中间件:
_layout
将此中间件添加到Configure方法:
public class GetRoutingMiddleware
{
private readonly RequestDelegate _next;
private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider;
public GetRoutingMiddleware(RequestDelegate next,IActionDescriptorCollectionProvider actionDescriptorCollectionProvider)
{
_next = next;
_actionDescriptorCollectionProvider = actionDescriptorCollectionProvider;
}
public async Task InvokeAsync(HttpContext context)
{
var allMenuList = _actionDescriptorCollectionProvider.ActionDescriptors.Items.Select(x => new
{
Action = x.RouteValues["Action"],Controller = x.RouteValues["Controller"],Name = x.AttributeRouteInfo != null ? x.AttributeRouteInfo.Name : "",Template = x.AttributeRouteInfo != null ? x.AttributeRouteInfo.Template : x.RouteValues["Controller"] + "/" + x.RouteValues["Action"],}).ToList();
var menu = allMenuList.GroupBy(x => x.Controller).ToList();
var subMenus = "";
foreach (var subMenuList in menu)
{
if (subMenuList.Count() > 0)
{
subMenus += "<li class=\"nav-item dropdown\"><a href=\"#\" class=\"nav-link dropdown-toggle\" role=\"button\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\"><span>" + subMenuList.Key + "</span></a>";
subMenus += "<div class=\"dropdown-menu\" arialabelledby=\"navbarDropdown\">";
foreach (var mnu in subMenuList)
{
subMenus += "<a class=\"dropdown-item\" href=\"/" + mnu.Template + "\">" + mnu.Action + "</a>";
}
subMenus += "</div>";
subMenus += "</li>";
}
else
{
subMenus += "<li class=\"nav-item\"><a href=\"/" + subMenuList.FirstOrDefault().Template + "\" class=\"nav-link\"><span>" + subMenuList.Key + "</span></a></li>";
}
}
context.Items.Add("routeMenu",subMenus);
await _next.Invoke(context);
}
}
在_Layout.cshtml中:
public void Configure(IApplicationBuilder app,IWebHostEnvironment env)
{
//...
app.UseStaticFiles();
app.UseMiddleware<GetRoutingMiddleware>();
app.UseRouting();
//....
}
我对样式进行了一些更改,您可以根据需要进行更改。
这是测试结果: