34

I would like to stop a few of my pages from showing up in search results. My understanding is that I add the following to the <head> section of the page:

<meta name="robots" content="noindex,nofollow"/>

The problem is that my pages use a common Layout page. Something like:

@{
    Layout = "~/Views/Shared/_VanillaLayout.cshtml";
}

Inside the layout page is the head section with a whole lot of links, scripts and meta tags. I don't want to duplicate this for indexable and non-indexable pages.

From my research I have found that: -

  • Having multiple <head> sections is bad.
  • Having the robot meta tag outside of head is bad.
  • Using robots.txt is more than I want and is bad.
  • Trying to pass a model into the layout is a bit of an overkill (need all models to inherit from some base and many pages are purely presentation and don't even have a model) and is bad.

Hopefully, I am missing something and there is a good (non-bad) way to do this or one of the approaches I have mentioned above is not so bad after all.

Community
  • 1
  • 1
acarlon
  • 14,908
  • 7
  • 66
  • 87

6 Answers6

70

It seems to me the easiest way would be to define a section in the <head> tag of your layout file that you can choose to populate with data in your views

<head>
    <meta charset="utf-8" />
    <title>@ViewBag.Title - My ASP.NET MVC Application</title>
    <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
    <meta name="viewport" content="width=device-width" />
    <!-- Adding a RenderSection here, mark it as not required-->
    @RenderSection("AdditionalMeta", false)
    @Styles.Render("~/Content/css")
</head>

Now, in any view in which you need to add additional meta data, simply add the following code at the end/beginning (after model declarations) of your view file

@section AdditionalMeta
{
    <meta name="robots" content="noindex,nofollow"/>
}

Since all of the Razor stuff is processed server side, there would be no issues in a) having JS append items given that some crawlers do not implement JS and b)no late appending to <head> tag/etc. Also, being marked as not required means that you only have to update the pages that you want to not be indexed and not have to set a variable on every single page in your application.

Tommy
  • 38,021
  • 8
  • 85
  • 116
  • 3
    Thank you! This answer inspired me to write a step-by-step tutorial on how to implement dynamic metatags from scratch. https://www.codebeaulieu.com/13/adding-meta-tags-dynamically – Dan Beaulieu Aug 10 '15 at 02:10
  • @Dan Beaulieu i can see in your site, to get the Meta details you have used `@Html.Action` , why not use `RenderPartial` , because performance-wise it's better to use RenderPartial as said [here](http://stackoverflow.com/a/5248218/2218697) in the comments. – Shaiju T Mar 21 '16 at 13:21
  • @DanBeaulieu your link is redirecting to `http://localhost:15536/adding-meta-tags-dynamically` very strange. Can you fix it? – Shiva May 29 '17 at 00:24
  • Thanks!! Nice article! – Shiva May 29 '17 at 06:52
8

You can add the following conditional with the meta-tag to the <head> element in your common layout:

<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
    @if (PageData["DisableIndexing"])
    {
        <meta name="robots" content="noindex,nofollow"/>  
    }    
    ...
</head>
<body>
    ...
</body>

That flag will be set as disabled by default in your main _ViewStart.cshtml file, the one in the Views folder. That would mean by default no page will add that meta tag. This will be the _ViewStart file:

@{
    Layout = "~/Views/Shared/_VanillaLayout.cshtml";
    PageData["DisableIndexing"] = false;
}

Finally, on pages where you want to disable indexing you just need to override that flag. For example if the Foo view should not allow indexing, you would do:

@model MyNamespace.MyFooModel

@{
    ViewBag.Title = "Foo";
    PageData["DisableIndexing"] = true;
}
...

If all the views within a certain folder should disable indexing, you could even add another _ViewStart.cshtml file to that folder where you would just set PageData["DisableIndexing"] = true;

As a side note, you could also use the ViewBag to pass data from the _ViewStart to the layout, but code is a bit ugly as you don't have direct access to the ViewBag in the ViewStart. See this answer if you prefer to use the ViewBag.

Community
  • 1
  • 1
Daniel J.G.
  • 31,175
  • 7
  • 96
  • 106
  • Thanks, this will work - I forgot about _ViewStart.cshtml. Tommy's answer is just a few lines less and 1 less file to change. – acarlon Jan 08 '14 at 11:50
  • 2
    @acarlon, that's another good and simple approach. I though about optional sections as well, but I decided for this approach because it would save you from repeating the meta tag on every view that disables indexing. But on the other hand, Tommy's approach is simpler and it is much more clear what tags are you adding to the view. – Daniel J.G. Jan 08 '14 at 11:54
7

If you are not defining any meta tag in Layout page and you simply want to add from your Page then you can do as following.

in your layout page _VanillaLayout.cshtml under head section use @RenderSection as following

<head>
<meta charset="utf-8">    
@RenderSection("SeoRender", false)
</head>

Now in your view page do following way

@{
Layout = "~/Views/Shared/_VanillaLayout.cshtml";
}

@section SeoRender{
@{        
<title>testTitle</title>
<meta name="keyword" content="testkeyword">
<meta name="description" content="testdescription">
<meta name="author" content="testauthor">   
}

So this you can define specifican meta tag and other thing individually in your page.

Dilip0165
  • 4,127
  • 4
  • 25
  • 33
0

Try with Jquery, in the page that you don't want to be indexed, add

$('head').append('<meta name="robots" content="noindex,nofollow"/>');

Edit:

another try could be (according to this Will Googlebot crawl changes to the DOM made with JavaScript? ) to try with simple javascript instead of jquery library

document.getElementsByTagName('head')[0].appendChild('<meta name="robots" content="noindex,nofollow"/>');
Community
  • 1
  • 1
theLaw
  • 1,110
  • 1
  • 10
  • 22
  • Nice thought, but I don't think jQuery is reliably executed by robots. Unless I am mistaken. – acarlon Jan 08 '14 at 10:59
  • according to this http://stackoverflow.com/questions/14336017/will-googlebot-crawl-changes-to-dom-made-with-javascript you can try to add javascript instead jquery, i add the edit – theLaw Jan 08 '14 at 11:05
0

Old question, but if it may helps someone, in the upper Layout, I had to use :

<head>
    @RenderSection("MySection", required:false)
</head>

Then, in every nested Layouts, I had to redefine my section :

@section MySection {
    @RenderSection("MySection", false)
}

Finally, I defined my section in my .cshtml view :

@section MySection{
    <meta name="robots" content="@Model.MetaContent"/>  

    @* or any other tag going to <head> *@
}
AlexB
  • 6,664
  • 12
  • 46
  • 66
0

Again, old question, but I figured out a very simple way to do this:

  1. Define some meta properties:
<meta property="og:type" content="website"/>
<meta property="og:url" content="https://illusive.azurewebsites.net/"/>
<meta property="og:image" content="https://illusive.azurewebsites.net/favicon.ico"/>
  1. Define your custom properties that you want to be different on each page (In your parent _Layout.cshtml):
<meta property="og:title" content="@ViewData["Title"]"/>
<meta property="og:description" content="@ViewData["Description"]"/>
  1. Define the ViewData elements for your different layouts:

(inside Index.html)

@model IndexModel
@{
    ViewData["Title"] = "Homepage";
    ViewData["Description"] = "Home Page";
}

(inside Error.cshtml)

@model ErrorModel
@{
    ViewData["Title"] = "Error";
    ViewData["Description"] = "An error has occurred!";
}

This should act as a way to easily customise your meta tags without having to use sections or any tedious blocks of code.

Jonny
  • 1