Building C# MVC Websites with a CMS can make it difficult to create structured data; which in turn fuels rich snippets on Google.

What are Rich Snippets?

Rich Snippets are a feature of most search engines that use structured data to provide a better user experience than traditional search results, and can give your website more visibility.

A rich snippet on Google, powered by structured data.

How to add structured data to a razor cshtml page

Structured data comes in three flavours, json-ld , RDFa and microdata . As RDFa and microdata have to be baked into the html, which can be difficult to retrospectively add to a template. For this reason, we will focus on json-ld , which can live in it’s own <script> tag.

In this tutorial we are going to add our json-ld on our razor template page. The example tutorial will be built on Umbraco 8, but the same methodology should apply to any C# MVC solution.

The example we are building is the Question & Answer Rich Snippet, but the concept applies to all rich snippets.

Include Newtonsoft Json.NET in your file. @using Newtonsoft.Json.Linq . It’s a commonly used library, and is available on NuGet. Pull your data from your CMS/Wherever it is stored. In this case we are using <IEnumberable<IPublishedElement>> but any loop-able datasource should work.

@{ var questions = Model.Value<IEnumerable<IPublishedElement>>("questions"); }

3. Next we need to replicate the structure of the ‘structured data’ with our Newtonsoft. Conveniently, Google provides examples of each type on their docs, or check out schema.org for a full documentation of how to use JSON-LD to build your structured data.

To start with, here is a final flat html example we are trying to replicate:



{

"

"

"mainEntity": {

"

"name": "How many ounces are there in a pound?",

"text": "I have taken up a new interest in baking and keep running across directions in ounces and pounds. I have to translate between them and was wondering how many ounces are in a pound?",

"answerCount": 3,

"upvoteCount": 26,

"dateCreated": "2016-07-23T21:11Z",

"author": {

"

"name": "New Baking User"

},

"acceptedAnswer": {

"

"text": "1 pound (lb) is equal to 16 ounces (oz).",

"dateCreated": "2016-11-02T21:11Z",

"upvoteCount": 1337,

"url": "

"author": {

"

"name": "SomeUser"

}

},

"suggestedAnswer": [

{

"

"text": "Are you looking for ounces or fluid ounces? If you are looking for fluid ounces there are 15.34 fluid ounces in a pound of water.",

"dateCreated": "2016-11-02T21:11Z",

"upvoteCount": 42,

"url": "

"author": {

"

"name": "AnotherUser"

}

}, {

"

"text": " I can't remember exactly, but I think 18 ounces in a lb. You might want to double check that.",

"dateCreated": "2016-11-06T21:11Z",

"upvoteCount": 0,

"url": "

"author": {

"

"name": "ConfusedUser"

}

}

]

}

}

</script> <a href="http://twitter.com/context" class="cm gg in io ip iq" rel="noopener">@context</a> ": " <a href="https://schema.org" class="cm gg in io ip iq" rel="noopener">https://schema.org</a> ", <a href="http://twitter.com/type" class="cm gg in io ip iq" rel="noopener">@type</a> ": "QAPage","mainEntity": { <a href="http://twitter.com/type" class="cm gg in io ip iq" rel="noopener">@type</a> ": "Question","name": "How many ounces are there in a pound?","text": "I have taken up a new interest in baking and keep running across directions in ounces and pounds. I have to translate between them and was wondering how many ounces are in a pound?","answerCount": 3,"upvoteCount": 26,"dateCreated": "2016-07-23T21:11Z","author": { <a href="http://twitter.com/type" class="cm gg in io ip iq" rel="noopener">@type</a> ": "Person","name": "New Baking User"},"acceptedAnswer": { <a href="http://twitter.com/type" class="cm gg in io ip iq" rel="noopener">@type</a> ": "Answer","text": "1 pound (lb) is equal to 16 ounces (oz).","dateCreated": "2016-11-02T21:11Z","upvoteCount": 1337,"url": " <a href="https://example.com/question1#acceptedAnswer" class="cm gg in io ip iq" rel="noopener">https://example.com/question1#acceptedAnswer</a> ","author": { <a href="http://twitter.com/type" class="cm gg in io ip iq" rel="noopener">@type</a> ": "Person","name": "SomeUser"},"suggestedAnswer": [ <a href="http://twitter.com/type" class="cm gg in io ip iq" rel="noopener">@type</a> ": "Answer","text": "Are you looking for ounces or fluid ounces? If you are looking for fluid ounces there are 15.34 fluid ounces in a pound of water.","dateCreated": "2016-11-02T21:11Z","upvoteCount": 42,"url": " <a href="https://example.com/question1#suggestedAnswer1" class="cm gg in io ip iq" rel="noopener">https://example.com/question1#suggestedAnswer1</a> ","author": { <a href="http://twitter.com/type" class="cm gg in io ip iq" rel="noopener">@type</a> ": "Person","name": "AnotherUser"}, { <a href="http://twitter.com/type" class="cm gg in io ip iq" rel="noopener">@type</a> ": "Answer","text": " I can't remember exactly, but I think 18 ounces in a lb. You might want to double check that.","dateCreated": "2016-11-06T21:11Z","upvoteCount": 0,"url": " <a href="https://example.com/question1#suggestedAnswer2" class="cm gg in io ip iq" rel="noopener">https://example.com/question1#suggestedAnswer2</a> ","author": { <a href="http://twitter.com/type" class="cm gg in io ip iq" rel="noopener">@type</a> ": "Person","name": "ConfusedUser"

Schema.org is particularly fussy about structure, so we need to match it verbatim. Luckily Newtonsoft is simple enough to use, with three main types to convert to json: JObject e.g. {} , JArray e.g. [] and JProperty e.g. "”:”” .

This means we use the following :

<script type="application/ld+json"> @{ var structuredData = new JObject( new JProperty("@context", "https://schema.org"), new JProperty("@type", "FAQPage"), new JProperty("mainEntity", new JArray( from item in questions select new JObject( new JProperty("@type", "Question"), new JProperty("name", (string)(item.GetProperty("question").Value().ToString())), new JProperty("acceptedAnswer", new JObject( new JProperty("@type", "Answer"), new JProperty("text", (string)(item.GetProperty("answer").Value().ToString())) ) ) ) ) ) ); } @Html.Raw(structuredData.ToString()) </script>

We are generating the matching code by declaring a var , building our JSON.NET object, and then rendering it out within the @Html.Raw as a string.

Newtonsoft will let us iterate over our enumerable (questions in this case) using from item in questions . This solution allows us the flexibility of using a dynamic data source on a per template basis, meaning that we could put this into a reusable partial and inject it only where needed.

Breaking down the core concepts of this example will allow you to produce any structured data format, and convert it from razor to json. Rich snippets are a big part of SEO nowadays, and it is important to include structured data in your webapp from very early on, while older sites can still be retrofitted to aid your ranking on search engines.

The full gist of the example can be found here. Like what you read? consider giving some 👏 👏 👏