3

我是一位经验丰富的 .NET 程序员,但我对整个 Web 编程这件事还是新手。我的 ASP.NET MVC 网站有一个全局布局,其中包括一些我想在控制器代码动态检测的条件下隐藏的内容(页面顶部的菜单链接)。

我的倾向 - 使用我迄今为止所了解的工具的简单方法 - 将 Boolean HideGlobal 值推入 ViewBag,并将全局标记放在我想隐藏在 @ 中的 _Layout.cshtml if (ViewBag.HideGlobal){} 块。

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

4

3 回答 3

8

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

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

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

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

~/Controllers/LayoutController.cs

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

        return View(model);
    }
}

~/Views/Layout/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>

~/Views/Shared/_Layout.cshtml

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

        <p>Stuff</p>
    </body>
</body>
于 2012-12-11T23:40:52.000 回答
3

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

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

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

@model Company.Project.BaseModel

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

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

@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
            }
        }
    }
}

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

于 2012-12-11T22:53:05.720 回答
2

这种类型的东西通常基于用户权限,这在操作过滤器而不是基本控制器中会更好。

是的,您必须使用ViewDataorViewBag但它实际上不是视图/模型的一部分,它在您的 _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也一样好。

于 2012-12-12T00:03:34.500 回答