ASP.NET MVC 3中替代ViewBag.Title的方法

26

ASP.NET MVC 3的新项目模板默认会将以下内容添加到默认布局(在Razor中是主页):

<title>@ViewBag.Title</title>

例如,视图必须包含以下内容以指定页面的标题:

@{
     ViewBag.Title = "Log On";
}

也许这只是我的个人偏好,但我发现使用ViewBag来保存标题有些不妥(我认为这样有点像魔术字符串)。所以我的问题是:对于使用ASP.NET MVC 3和Razor的人来说,这是否是推荐的最佳实践(使用动态属性包),还是您选择了更强类型的东西(可能涉及自定义基类)?


2
使用ViewBag非常好,因为您可以在布局页面中声明变量,然后为从它继承的每个视图指定不同的标题。如果不使用静态类型模型,实际上没有其他方法可以做到这一点。 - The Muffin Man
8个回答

28

我认为asp.net MVC 3默认的标题处理功能没有任何问题,可以使用。

个人而言,我使用以下代码来处理标题,我不是在推荐以下代码或者说它比默认功能更好,这只是我的个人喜好。

Master

<title>
    @RenderSection("Title");
</title>

查看

@section Title
{
    write title
}

我建议改进默认功能的一件事情

@{
    string pageTitle = @ViewBag.Title ?? "Title Not Set";
}
<title>@pageTitle</title>

所以每当您忘记在viewbag中添加它时,页面将显示title = Title Not Set

创建一个基类然后让所有控制器继承自该基类也可以实现相同的效果。但我认为这对于title来说过于繁琐。


只是为了澄清(我没有考虑默认控制器基类,我想你可以为视图创建自己的派生基类(我认为Razor允许这样做),并在此类上公开一个PageTitle属性,视图可以分配并且布局可以呈现)。 - soren.enemaerke
1
我喜欢这种 @ViewBag.Title ?? "Default" 的方法。它可以移动到 _ViewStart.cshtml 文件中,您可以在此设置所有共享属性的默认值。 - Darmak
@soren.enemaerke:假设您为视图创建了一个基类来处理页面标题,可能在视图内您会像这样设置标题@{this.pageTitle="New Title";},而使用默认功能,您可以像这样设置标题@{ ViewBag.Title = "New Title";}。语法上没有太大的区别。使用此代码的另一个好处是,您可以在视图或控制器中设置标题,两者都可以正常工作。 - Praveen Prasad
接受这个答案,因为它似乎总结了回答的一般感觉:(1)动态并不邪恶,(2)你可以进行一些轻微的改进。 - soren.enemaerke
使用部分的建议很好! - sky-dev

7

ViewBag用于标题是完全可以的(我甚至会说这就是使用ViewBag的目的)- 动态语言并不是绝对的邪恶。 "Title" 是众所周知的,在视图模板中不太可能改变,甚至是预定义的。我个人使用以下标题:

<title>@(ViewBag.Title == null ? string.Empty : ViewBag.Title + " | ")Site Name</title>

如果您担心打错 ViewBag.Title,您可以通过创建自定义的 WebViewPage 来使其成为强类型,但是在该强类型属性中仍然需要使用 ViewBag 或者可能是 HttpContext.Items,因为在渲染期间会创建多个 WebViewPage 实例。
我建议坚持使用 ViewBag,因为创建自己的 WebViewPage 看起来有些过度设计,即使在已经拥有自定义 WebViewPage 的情况下,在其中创建单个属性也是毫无意义的复杂化。这是一个经常过度工程化的人的观点。

或者只需使用<title>@(ViewBag.Title ?? ViewBag.Title + " | ")Site Name</title>,以使其尽可能简短。 - schaermu
@schaermu你的建议不起作用,如果Title属性没有被设置,它会导致| 网站名称 - Professor of programming

3
我完全不使用 ViewBag。
在 _Layout.shtml 的顶部...
@model <YourWebAppNameSpace>.Models.Base.EveryPageViewModel

在 _Layout.shtml 中...
<title>@Model.Title</title>

在您的模型中...

/// <summary>
/// Index View Model
/// </summary>
public class IndexViewViewModel : EveryPageViewModel {

}

在每个页面视图模型中

/// <summary>
/// Every Page View Model
/// </summary>
public abstract class EveryPageViewModel {
    /// <summary>
    /// Title
    /// </summary>
    public string Title { get; set; }
    /// <summary>
    /// Sub Title
    /// </summary>
    public string SubTitle { get; set; }
}

在您的控制器操作中:
    /// <summary>
    /// Index
    /// </summary>
    /// <returns></returns>
    public ActionResult Index() {
        var model = new IndexViewViewModel();
        model.Title = "Home";
        return View(model);
    }

2
我更喜欢创建一个PageTitle ActionFilter属性,而不是编辑单个的ViewBags。
用法: 保持视图不变。
<title>@ViewBag.Title</title>

控制器全局页面标题:

[PageTitle("Manage Users")]
public class UsersController : Controller {
    //actions here
}

对于个人用户:

public class UsersController : Controller {
    [PageTitle("Edit Users")]
    public ActionResult Edit(int id) {
          //method here
    }
}

属性代码:

public class PageTitleAttribute : ActionFilterAttribute
{
    private readonly string _pageTitle;
    public PageTitleAttribute(string pageTitle)
    {
        _pageTitle = pageTitle;
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        base.OnActionExecuted(filterContext);
        var result = filterContext.Result as ViewResult;
        if (result != null)
        {
            result.ViewBag.Title = _pageTitle;
        }
    }
}

易于管理,功能强大。

页面标题应该在视图中设置,而不是控制器中设置。 - Professor of programming
它应该吗?假设您重用视图以上传不同类型的文件?例如,MyFiles/UploadExcel,MyFiles/UploadCsv... - nh43de

1

我们更喜欢强标题设置...从我们的BaseController类中选取几个样例。(页面定义封装的视图模型)

protected override ViewResult View(string viewName, string masterName, object model)
{
    if (model is Page)
    {
        ViewBag.Title = ((Page)model).Title;
        //HACK: SEO
        //TODO: SEO
    }
    return base.View(viewName, masterName, model);
}

1

使用ViewBag.Title = "My Title" 没有任何问题。

你所做的只是使用一个动态属性。

问题实际上是信息应该在哪里“声明”。

也就是说,它对于手头的目的来说最容易访问的地方在哪里。

如果它是基于每个页面的基础,那么那就是正确的地方。

然而,如果页面的标题可以从模型中派生出来,那么你应该这样做。

在这种情况下,我可能会为你使用的ViewModel创建一个基类,并在那里创建一个PageTitle属性,其中包含从模型属性派生页面标题的逻辑。

所以:

<title>Model.PageTitle</title>

总结一下,因地制宜,并不要害怕使用动态属性……只要你理解它们的含义和作用。

1

就我个人而言,我认为这种情况是对 ViewBag 的可接受使用。它仅限于一个“众所周知”的属性,并且很可能不会在未来引起任何问题。最终,一切都是关于实用主义和找到尽可能快的方法。在需要设置标题的基类中,我认为编写太多代码以获得类型安全性是不值得的。

祝好运!


1

我认为只要你想设置的是标题,使用ViewBag就可以了。好吧,也许不仅仅是标题——最多2-3个属性。

但是如果你开始在每个控制器操作中设置越来越多(常见的)属性,我会选择强类型的“ViewModelBase类”。但这只是我的看法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接