关于_Layout.cshtml的MVC决策

时间:2015-12-03 16:31:52

标签: c# asp.net-mvc inversion-of-control

所以我浏览了一下,似乎无法找到解决问题的合适方法。

问题

在我的布局中,我希望能够根据数据库中的内容选择运行时是否存在导航项:

当前布局(导航栏)

<div class="navbar-collapse collapse">
   <ul class="nav navbar-nav">
       <li>@Html.ActionLink("Dashboard", "Index", "Dashboard")</li>
           <li>@Html.ActionLink("NzbGet", "Index", "NzbGet")</li>
              <li>@Html.ActionLink("Plex", "Index", "Plex")</li>
              <li>@Html.ActionLink("Settings", "Index", "Settings")</li>
           </ul>
       </div>

我如何决定看哪一个展示:

public PrincipleExtension(ISettingsService<SabNzbSettingsDto> sab)
{
    SabService = sab;
}

private ISettingsService<SabNzbSettingsDto> SabService { get; set; }    
public bool IsApplicationEnabled(IPrincipal principal, Applications application)
{
    switch (application)
    {
        case Applications.SabNZBD:
            return SabService.GetSettings().Enabled;
            //...
     }
     return false;
 }

现在,PrincipleExtension最初是IPrincipal上的扩展方法。但现在这是不可能的,因为我使用的是IoC容器,并且不想对任何依赖项进行硬编码。

所以在它是静态方法之前我可以做User.IsApplicationEnabled(Applications.SabNZBD)

如何在布局中检查应用程序是否已将启用标志设置为true?有什么想法吗?

感谢。

3 个答案:

答案 0 :(得分:2)

将菜单HTML移动到PartialView,并将其作为ActionResult从Controller Action返回。

<div class="navbar-collapse collapse">
    <ul class="nav navbar-nav">
        @foreach (var item in Model)
        {
            <li><a href="@item.Url">@item.Name</a></li>
        }
    </ul>
</div>

让控制器确定哪些菜单项存在并将新模型发送到PartialView。

public ActionResult ProductsMenu()
{
    var listOfAvailableProducts = GetAvialableProducts(Principal); //to implement elsewhere
    var productsMenuItems = new List<ProductMenuItem>();

    for(var i in listOfAvailableProducts)
    {
        productsMenuItems.Add(new ProductMenuItem
            {
                Id = i.id,
                Name = i.name,
                Url = "//example.com/there"
            }
        );
    }

    return PartialView("/path/to/_ProductsMenu.cshtml", productsMenuItems);
}

然后在_Layout.cshtml razor视图中调用它:

@{ Html.RenderAction("ActionName","ControllerName"); }

答案 1 :(得分:1)

您可能需要查看名为MVCSitemapProvider的nuget包。

它具有引导程序互操作性,您可以使用它在运行时动态生成导航,使您可以在任何给定时间检查导航的状态/状态。

https://github.com/maartenba/MvcSiteMapProvider/wiki/Defining-sitemap-nodes-using-IDynamicNodeProvider

此链接显示您可以随时动态生成导航节点:

public class StoreDetailsDynamicNodeProvider 
: DynamicNodeProviderBase 
{ 
public override IEnumerable<DynamicNode> GetDynamicNodeCollection(ISiteMapNode node) 
{
    using (var storeDB = new MusicStoreEntities())
    {
        // Create a node for each album 
        foreach (var album in storeDB.Albums.Include("Genre")) 
        { 
            DynamicNode dynamicNode = new DynamicNode(); 
            dynamicNode.Title = album.Title; 
            dynamicNode.ParentKey = "Genre_" + album.Genre.Name; 
            dynamicNode.RouteValues.Add("id", album.AlbumId);

            yield return dynamicNode;
        }
    }
} 
}

这种方法的另一个好处是它带回了Sitemap.xml-esque功能,允许您同时分配静态和动态导航。

这是我的菜单displaytemplate的一个例子:

@model MenuHelperModel

<div class="navbar navbar-inverse navbar-static-top hidden-print">
<div class="container">
    <div class="navbar-header">
        <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navContainer">
            <span class="sr-only">Toggle Navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
        </button>
        <a href="~/" class="navbar-brand">AH Operations&nbsp;<i class="glyphicon glyphicon-home"></i></a>
    </div>
    <div class="collapse navbar-collapse" id="navContainer">
        <ul class="nav navbar-nav" role="menu" aria-labelledby="dropdownMenu">
            @foreach (var node in Model.Nodes)
{
    if (node.Title == "Separator")
    {
                <li class="nav-divider"></li>
    }
    else if (node.Children.Any())
    {
        if (node.IsCurrentNode || node.IsInCurrentPath)
        {
                <li class="active dropdown">
                    @Html.DisplayFor(m => node)
                    @Html.DisplayFor(m => node.Children)
                </li>
        }
        else
        {
                <li class="dropdown">
                    @Html.DisplayFor(m => node)
                    @Html.DisplayFor(m => node.Children)
                </li>
        }
    }
    else
    {
        if (node.IsCurrentNode || node.IsInCurrentPath)
        {
                <li class="active">
                    @Html.DisplayFor(m => node)
                </li>
        }
        else
        {
                <li>
                    @Html.DisplayFor(m => node)
                </li>
        }
    }
}
        </ul>
        @Html.Partial("_LoginPartial")
    </div>
</div>

要使其与Bootstrap 3中删除的无限n + 1子菜单样式一起使用,请添加此CSS:

.navbar-user {
font-size: 14px !important;
}

.dropdown-submenu {
position: relative;
}

.dropdown-submenu > .dropdown-menu {
    top: 0;
    left: 100%;
    margin-top: -6px;
    margin-left: -1px;
    -webkit-border-radius: 0 6px 6px 6px;
    -moz-border-radius: 0 6px 6px 6px;
    border-radius: 0 6px 6px 6px;
}

.dropdown-submenu > a:after {
    display: block;
    content: " ";
    float: right;
    width: 0;
    height: 0;
    border-color: transparent;
    border-style: solid;
    border-width: 5px 0 5px 5px;
    border-left-color: #cccccc;
    margin-top: 5px;
    margin-right: -10px;
}

.dropdown-submenu:hover > a:after {
    border-left-color: #ffffff;
}

.dropdown-submenu.pull-left {
    float: none;
}

    .dropdown-submenu.pull-left > .dropdown-menu {
        left: -100%;
        margin-left: 10px;
        -webkit-border-radius: 6px 0 6px 6px;
        -moz-border-radius: 6px 0 6px 6px;
        border-radius: 6px 0 6px 6px;
    }

答案 2 :(得分:0)

我将创建一个全局ActionFilter并覆盖OnActionExecuting方法,以便在每个请求的ViewBag中放置您的标志。您还可以创建一个HtmlHelper扩展方法。