Razor代码以编程方式隐藏全局菜单项?

时间:2012-12-11 22:35:10

标签: asp.net-mvc razor

我是一名经验丰富的.NET程序员,但我对这整个网络编程工作都很陌生。我的ASP.NET MVC网站有一个全局布局,其中包含一些内容(页面顶部的菜单链接),我想在控制器代码动态检测到的条件下隐藏它们。

我的倾向 - 使用我迄今为止学到的工具的简单方法 - 将布尔的HideGlobal值推入ViewBag,并将全局标记放在我要隐藏的_Layout.cshtml中一个@if(ViewBag.HideGlobal){}块。

我只是想知道这是否是“正确”的方式,或者是否有一些我应该使用的Razor魔法,原因对我来说还不明显?

3 个答案:

答案 0 :(得分:8)

我不喜欢在动作返回的视图之外使用动作的视图模型。在这种情况下使用基本视图模型非常笨重。

我认为使用单独的(子)动作更清晰,更明显,该动作包含指定全局菜单应如何显示的逻辑。此操作返回全局菜单视图。从布局页面调用该操作。

或者您可以为确定菜单状态的整个标题创建操作 - 或者执行if / else以呈现全局菜单的部分视图。

下面的示例封装了标题/全局菜单的需求,并提供了一种更改标题/菜单的未来验证方式,对代码基础结构(基本视图模型)的影响最小。

<强>〜/控制器/ LayoutController.cs

public class LayoutController : Controller
{
    [ChildActionOnly]
    public ActionResult Header()
    {
        var model = new HeaderViewModel();
        model.ShowGlobalMenu = ShowGobalMenu();

        return View(model);
    }
}

<强>〜/查看/布局/ Header.cshtml

@model HeaderViewModel
@{
    Layout = "";
}

<header>
    <a href="/">Home</a>

    @if(Model.ShowGlobalMenu)
    {
        <ul>
            <li><a href="#">Link</a></li>
            <li><a href="#">Link</a></li>
            <li><a href="#">Link</a></li>
            <li><a href="#">Link</a></li>
        </ul>
    }
</header>

<强>〜/查看/共享/ _Layout.cshtml

<html>
    <body>
        @Html.Action("Header", "Layout")

        <p>Stuff</p>
    </body>
</body>

答案 1 :(得分:3)

你所描述的内容(将一个bool放入ViewBag)可以正常工作。但就个人而言,我喜欢强类型模型体验,所以当我想要像你在主/布局页面中描述的UI逻辑那样(我几乎总是如此)时,我更喜欢将这些标志放入基本模型中我的其他模特继承自。

public class BaseModel
{
     public bool HideGlobal { get; set; }
}

在_Layout.cshtml页面的顶部,我指定我期待一个BaseModel:

@model Company.Project.BaseModel

当然,其他视图可能需要其他模型类型,但如果它们使用此布局,那么这些模型类型应该来自BaseModel。

最后,当我想检查标志时,而不是在ViewBag中有一个神秘的,未记录的字段,我有一个可爱的intellisense和感觉良好的强类型模型成员:

@if (!Model.HideGlobal)
{
    <div>...</div>
}

编辑:我应该补充说,通常还有一个基本控制器,它的工作就是填充BaseModel中的字段。我的通常看起来像这样:

public class BaseController : Controller
{
    protected override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        var result = filterContext.Result as ViewResultBase;
        if (result != null)
        {
            var baseModel = result.Model as BaseModel;
            if (baseModel != null)
            {
                //Set HideGlobal and other BaseModel properties here
            }
        }
    }
}

这里的第一个答案,温柔: - )

答案 2 :(得分:2)

这种类型的东西通常基于用户权限,这在Action Filter而不是基本控制器中要好得多。

是的,您必须使用ViewDataViewBag,但它实际上不是视图/模型的一部分,它在_layout.cshtml中更高

操作过滤器

public class UserAccessAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting( ActionExecutingContext filterContext ) {
        var hasAccessToMenu = /* Code */;

        filterContext.Controller.ViewData["GlobalVisible"] = hasAccessToMenu;
    }
}

查看(_layout.cshtml)

@if(ViewData["GlobalVisible"])
{
    <ul>
        <li><a href="#">Link</a></li>
        <li><a href="#">Link</a></li>
        <li><a href="#">Link</a></li>
        <li><a href="#">Link</a></li>
    </ul>
}

这使您可以将此逻辑从控制器中分离出来,因为它是全局的,这很重要。

此外,我在我的示例中使用了ViewData,但使用ViewBag也同样出色。