Alternative to ViewBag.Title in ASP.NET MVC 3

2020-05-24 23:27发布

问题:

By default the new project template for ASP.NET MVC 3 adds the following to the default layout (masterpage in razor):

<title>@ViewBag.Title</title>

The view must then contain the following to assign the title of the page, for instance:

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

Perhaps it is just my own preference but I find that using the ViewBag to hold the title a little bit wrong (I'm thinking too much magic-string flavor). So my question is: Is this the recommended best practice for people using ASP.NET MVC 3 and razor (using a dynamic property bag) or are you opting for something more strongly typed (perhaps involving a custom baseclass?)

回答1:

I don't think there is any thing bad with default title handling feature that ships with asp.net MVC 3, its okay to do.

I personally do this(below written) to handle title, I am not endorsing the below code or saying that its better than default functionality, its just a preference.

Master

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

View

@section Title
{
    write title
}

One thing i could suggest to improve default functionality

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

So whenever you forget to add it in viewbag, the page will display title= Title Not Set

Creating a base class then making all your controllers inherit from that base-class can also be done. But I think its taking so much of pain for title.



回答2:

ViewBag for title is perfectly fine (I'd even say it is the purpose of having ViewBag) - dynamic is not the absolute evil. "Title" is well known, unlikely to change and even predefined in view templates. I personally use following title:

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

If you are worried about mistyping ViewBag.Title you can make it strong type by creating custom WebViewPage but you will still have to use ViewBag or maybe HttpContext.Items inside that strongly typed property because there are multiple instances of WebViewPage created during rendering IIRC.

I'd recommend to stick with ViewBag, creating own WebViewPage because of this seems like overkill - even creating single property on it if you already have custom WebViewPage is in my opinion just worthless complication - and that comes from person that is often overengineering things.



回答3:

I also do not use the ViewBag, at all.

At the top of _Layout.shtml ...

@model <YourWebAppNameSpace>.Models.Base.EveryPageViewModel

In _Layout.shtml ...

<title>@Model.Title</title>

In your Model ...

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

}

In 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; }
}

In your controller action

    /// <summary>
    /// Index
    /// </summary>
    /// <returns></returns>
    public ActionResult Index() {
        var model = new IndexViewViewModel();
        model.Title = "Home";
        return View(model);
    }


回答4:

I like to create a PageTitle ActionFilter attributes rather than editing individual ViewBags

Usage: keep the view the same

<title>@ViewBag.Title</title>

For controller-wide page title:

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

For individual views:

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

Attribute Code:

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

Easy to manage and works like a charm.



回答5:

For me personally, I think this case is an acceptable use of ViewBag. It is limited to a "well-known" property, and it likely won't cause any problems in the future. In the end, it is all about being pragmatic and finding a way to be as quick as possible. Having a base class where you need to set the title would in my opinion be too much code to be worth the type safety.

Good luck!



回答6:

I would say that as long as it's only the Title you want to set, it's ok to use the ViewBag. Well, maybe not only - at most 2-3 properties.

But if you start to see you're setting more and more (common) properties in every controller action, I would go with a strongly typed "ViewModelBase class". But it's just me.



回答7:

we prefer strong title setting.. few sample from our BaseController class. (Page defines encapsulated view modal)

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);
}


回答8:

There is nothing wrong with using ViewBag.Title = "My Title";

All you are doing is use a dynamic property.

The question is really where the information should be "declared".

Ie, where is it most accessible for the purposes at hand.

If it is on a per page basis, then that is the right place.

If, however, the title of the page can be derived from the Model, then you should do that.

In this case, I would probably use a base class for the ViewModel that you use, and create a PageTitle property there that contains the logic to derive the page title from properties in the Model.

So:

<title>Model.PageTitle</title>

In summary, horses for courses and don't be afraid of using dynamic properties... so long as you understand what they are and what they do.