29

I was wondering what, if there is one, is the best practice for including SEO content such as meta descriptions and keywords in an ASP.NET MVC (I'm using v3 RC) view. My initial plan is to create an actionfilter, applied globally to actions, to pull the relevant data from a data store and pass it as viewdata to the view.

My questions are: 1) Do you foresee any problems with this approach? 2) Are there any more suitable approaches? 3) what is an appropriate data store to use here - should i pull from the DB (or cache if the data is available), use resource files, config files, etc?

Thanks in advance,

JP

Jim G.
  • 15,141
  • 22
  • 103
  • 166
JP.
  • 5,536
  • 7
  • 58
  • 100
  • 1
    If I do not misunderstand, Google does not use data from Meta tag anymore because it's easy to fake. They extract data from real user-content and put it into their algorithm for indexing it. –  Dec 03 '10 at 09:12

5 Answers5

27

I would use attributes on my controller actions and add them to the ViewData in my base controller in the method OnExecutingAction.

The motivation to put it in the controller and not the view is that it's really more information about the actual action than about the view. And you can use it when returning different kinds of formats like json or xml.

Controller

class MyController
{

  [MetaKeywords("hello,world,something,else")]
  [MetaDescription("Tells you how to greet the world")]
  ActionResult Hello()
  {
      return View();
  }
}

You could always use a resource file instead of plain strings.

in base controller:

    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var keywords = filterContext.ActionDescriptor.GetCustomAttributes(typeof(MetaKeywordsAttribute), false);
        if (keywords.Length == 1)
            ViewData["MetaKeywords"] = keywords.Value;

        var description = filterContext.ActionDescriptor.GetCustomAttributes(typeof(MetaDescriptionAttribute), false);
        if (description.Length == 1)
            ViewData["MetaDescription"] = description.Value;

        base.OnActionExecuting(filterContext);
    }

In your layout

<meta name="keywords" value="@View.MetaKeywords" />

And here is the answers your questions: =)

1) Do you foresee any problems with this approach?

Nope. It's a fine approach.

2) Are there any more suitable approaches?

Just gave you an alternative.

3) what is an appropriate data store to use here - should i pull from the DB (or cache if the data is available), use resource files, config files, etc?

I would put it in plain text (if you don't have to support multiple languages), else in a resource file. This information is typically not changed unless the view or controller is changed (where a recompilation is needed anyway). Hence no need for a more dynamic source.

jgauffin
  • 99,844
  • 45
  • 235
  • 372
  • I do not recommend you to fix keyword and description in attribute because it hard to modify or config. You need to rebuild and redeploy website for updating it. –  Dec 03 '10 at 09:15
  • Not if the strings are in a resource file. And how often do you change them without modifying other things in the project? – jgauffin Dec 03 '10 at 09:18
  • @igaufflin Could you provide please a link or an explenation about what is a "base controller"? – Ricardo Polo Jaramillo Aug 19 '12 at 17:50
  • @RicardoPolo Create a new controller which all your other controllers inherit. – jgauffin Aug 19 '12 at 18:31
  • does this approach still work if my path is like this: www.mywebsite.com/team/roster/{rosterid}/{rostername} – ganders Oct 08 '15 at 19:18
  • gotcah, so I can't/shouldn't put my {rostername} in the meta description? – ganders Oct 08 '15 at 19:21
  • no, it wouldn't get translated unless you manually modify the metadata in the OnActionExecuting. – jgauffin Oct 08 '15 at 19:23
  • Right, that's what I mean. If I DIDN'T use your approach, and sent the meta data back in the viewmodel. Reason is because there are 1000's of pages that would follow that template, and I'm wondering if my SEO score would go DOWN since 1000's of pages would have the same meta description – ganders Oct 08 '15 at 19:27
  • @ganders: No. I mean like this: https://gist.github.com/jgauffin/55b1ce86c7e5fc5cced8. You could generate metadata by just using route information too. – jgauffin Oct 08 '15 at 19:36
20

Another approach would be to simply use in _Layout.cshtml:

    <html>
    <head>
         <title>@ViewBag.Title</title>
         <meta name="description" content="@ViewBag.MetaDescription" />
         <meta name="keywords" content="@ViewBag.MetaKeywords" />
    </head>
    <body>

And in your views you cand define separately for each view the corresponding title/description/keywords:

For example in Home/Index.cshtml use:

@{
    ViewBag.Title = "Home page title | samplePage.com";
    ViewBag.MetaDescription = "Home page meta description";
    ViewBag.MetaKeywords = "meta keywords keyword home page";
}
Pinte Dani
  • 1,989
  • 3
  • 28
  • 35
  • 7
    So simple. This is really the best solution. I don't agree with everyone saying that you should put this stuff in the controller. As an SEO and a programmer i can say this is the most manageable way to do it. Who wants to recomplile every time they tweak a meta description. This makes it easier to test and update. Kudos. – KingOfHypocrites Mar 02 '15 at 02:27
  • 1
    I also agree with Dani that this is the best way to do it. I's easily manageable and an elegant solution. – memory of a dream Apr 15 '16 at 14:36
  • 2
    I added `@if (!String.IsNullOrWhiteSpace(ViewBag.MetaDescription)) { } @if (!String.IsNullOrWhiteSpace(ViewBag.MetaKeywords)) { }` so that I did not have to put meta data on every page. – ChrisFox May 22 '16 at 11:28
  • Thanks Chris was looking for a way to implement default metas. – Sagi Feb 11 '18 at 07:50
15

Add optional section to your layout page:

<!DOCTYPE html>
<html>
<head>
  @RenderSection("ExtraHeadContent", required: false)
</head>
<body>

Now you can define meta tags on any content page using @section:

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}
 
@section ExtraHeadContent {
    <meta name="description" content="My super page">
}
 
<div>The main content</div>

See Optional Razor Sections with Default Content by Marcin Doboz.

Pavel Chuchuva
  • 22,633
  • 10
  • 99
  • 115
5

1) Do you foresee any problems with this approach?

No.

2) Are there any more suitable approaches?

I would write a helper method for this or use a child action along with the Html.Action helper because you will be pulling data from the database.

3) what is an appropriate data store to use here - should i pull from the DB (or cache if the data is available), use resource files, config files, etc?

This will depend on what your site is doing, how it is organized, where is the information stored, ...

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
5

If you are using a master page, you can create content placeholders to house the keywords and description, which you render on the view from data in the Model. The data in the Model can either come directly from a database field or from a helper that generates it based on other stuff!

Master Page:

<asp:contentplaceholder id="MetaTags" runat="server" />

View:

<asp:Content ID="Content1" ContentPlaceHolderID="MetaTags" runat="server">
    <meta name="keywords" content="<%= Model.Keywords %>">
    <meta name="description" content="<%= Model.Description %>">
</asp:Content>
Fenton
  • 241,084
  • 71
  • 387
  • 401
  • I agree with this answer. Always keep it clean and easy to modify. It is truly MVC concept. –  Dec 03 '10 at 09:16
  • I would actually use the Razor equivalent of this these days (Pavel Chuchuva's answer already has the Razor version) - but yes, I'm not a fan of ViewBag on the whole and I definitely wouldn't hard-code strings in attributes as these need to change often to stay in sync with the actual page content. – Fenton Sep 14 '15 at 07:16