Using MVC Razor With Kentico CMS 7

   —   

As you may know, we have improved our MVC support in Kentico CMS 7. Let's see how you can easily use Razor view engine to render your content.

Hi there,

I originally planned to write this article about a month ago, but I was quite busy with planning and organizing v8 after Kentico Connections, so I didn't have chance to do it until now.

I want to quickly show you how you can leverage MVC support in Kentico CMS 7, and render your content with the Razor view engine. In this particular example, I will use Kentico CMS 7 final version with the .NET 4.0 Web site project.

Before I configure the pages to use it, I will first prepare the controller and view. To do that, open your web site project in Visual Studio and locate following folders:

  • ~/App_Code/Controllers
  • ~/Views

These are the only folders you need to modify. First, we will prepare the controller. Create a new file ~/App_Code/Controllers/Global/NewsRazorController.cs, with the following code:

using System; using System.Data; using System.Web.Mvc; using CMS.CMSHelper; using CMS.DocumentEngine; using CMS.URLRewritingEngine; namespace CMS.Controllers.Global { /// <summary> /// Sample controller for the news. /// </summary> public class NewsRazorController : Controller { /// <summary> /// Process the detail action. /// </summary> public ActionResult List() { // Prepare the data for view var documents = TreeHelper.GetDocuments(CMSContext.CurrentSiteName, "/News/%", CMSContext.PreferredCultureCode, true, "CMS.News", null, "NewsReleaseDate DESC", -1, true, 0); return View(documents); } /// <summary> /// Process the detail action. /// </summary> public ActionResult Detail() { // Prepare the data for view TreeNode document = TreeHelper.GetDocument(CMSContext.CurrentSiteName, "/News/" + RouteData.Values["id"], CMSContext.PreferredCultureCode, true, "CMS.News", true); if (document != null) { document.SetValue("NewsTitle", document.GetValue("NewsTitle")); return View(document); } else { // Document not found URLRewriter.PageNotFound(); return null; } } } }


The controller will serve the same content as the sample NewsMVC controller (list of news and news detail), but I wanted to keep this separated.

Then create new file ~/Views/NewsRazor/Master.cshtml, which will serve as the master page for both views:

@inherits System.Web.Mvc.WebViewPage <html xmlns="http://www.w3.org/1999/xhtml"> <head id="Head1"> <title>News MVC Razor</title> <link rel="stylesheet" type="text/css" href="~/CMSPages/GetResource.ashx?stylesheetname=CorporateSite" /> </head> <body> <div class="zoneMainContent"> <div class="zoneTopWrap"> <div class="inner"> <!-- Logo --> <div class="zoneLogo"> <a href="~/Home.aspx" title="Home page"> <img class="logo" src="~/Images/CorporateSiteLogo.aspx?width=183&height=47" alt="Logo" style="border-width: 0px;" /> </a> </div> <div class="clear"> </div> <br /> <!-- Menu --> <div class="zoneMenu">   <div class="clear"> </div> </div> </div> </div> <div class="zoneMenuWrap"> <div class="inner"> <div class="zoneBreadcrumbs"> </div> <div class="clear"> </div> </div> </div> <!-- Content --> <div class="zoneMainContent"> @RenderBody() <div class="clear"> </div> </div> </div> <!-- Footer zone --> <div class="zoneFooter"> <div class="inner"> <div class="footerLogo"> <h3>Powered by</h3> <a href="http://www.kentico.com" title="Kentico CMS for ASP.NET - the WEB 2.0 Content Management System for .NET developers"> <img border="0" src="~/App_Themes/CorporateSite/Images/PoweredByKentico.png" alt="This web site uses Kentico CMS, the content management system for ASP.NET developers." /></a> </div> <div class="clear"> </div> </div> </div> </body> </html>


Create also two additional files for the views. First one named ~/Views/NewsRazor/List.cshtml which displays a list of news:

@inherits System.Web.Mvc.WebViewPage<CMS.DocumentEngine.TreeNodeDataSet> @using CMS.DocumentEngine; @using CMS.GlobalHelper; @{ Layout = "~/Views/NewsRazor/Master.cshtml"; } <div class="innerContent"> <h1>MVC Example - Razor</h1> <p> This is a sample for the page rendered by MVC Razor view engine. It displays the news list. The list is routed by using Route URL pattern <strong>/NewsRazor/List</strong> to provide extension-less URL, and then displayed with an MVC page template type using <strong>Razor</strong> controller and <strong>~/Views/Razor/List.cshtml</strong> view. </p> <div class="LightGradientBox "> @foreach (var doc in Model) { <h2> <a href="@URLHelper.ResolveUrl("~/newsrazor/detail/" + doc.NodeAlias)"> @doc.GetValue("NewsTitle") </a> </h2> <p> @Html.Raw((string)doc.GetValue("NewsText")) </p> } </div> </div> <div class="clear"> </div>


And second one named ~/Views/NewsRazor/Detail.cshtml, which displays the detail of particular news document:

@inherits System.Web.Mvc.WebViewPage<CMS.DocumentEngine.TreeNode> @using CMS.GlobalHelper; @{ Layout = "~/Views/NewsRazor/Master.cshtml"; } <div class="innerContent"> <h1>MVC Example - Razor</h1> <p> This is a sample for the page rendered by MVC Razor view engine. It displays the news detail. The detail is provided by <strong>NewsRazor</strong> controller and <strong>~/Views/NewsRazor/Detail.cshtml</strong> view and routed through MVC URL pattern <strong>/NewsRazor/Detail/{id}</strong> added as document alias to the same document as the main document. This way, there is no need to provide separate documents for detail view. </p> <div class="LightGradientBox "> <h2> @Model.GetValue("NewsTitle")</h2> <p> @Html.Raw((string)Model.GetValue("NewsText")) </p> <p> <a href="@URLHelper.ResolveUrl("~/newsrazor/list/")">Back to the list of news</a> </p> </div> </div>


As you can see, both views use the Master.cshtml as their Layout (master) view.

You may also notice, that I am not creating these views in folder Global as our MVC example. The reason for it is that Kentico CMS 7 does not provide an overriden view factory for Razor, therefore the views must be in their default location. That is because v7 is also compiled against ASP.NET 3.5 which didn&#39;t allow us to add it. We will provide the full support including multisite view support also for Razor in v8.

Now we are ready to display the content. As my project is a web site project, I don&#39;t need to compile it. If you have a web application project, you need to compile it first to make the controller class available to the application.

Now go to CMS Site Manager and register new Page template set up as shown in following picture:

NewsRazor.png

This template will provide us with the basic view of the document displaying list of news.

Now go to CMS Desk -> Content and create a new document using your page template. It can be placed anywhere, I will create it in the root of the web site.

NewPageRazor.png

The last step is to set up URLs for this document. First, we set the default URL path of the document to route /NewsRazor/List, to get a nice and extensionless URL for the main view of the document.

RazorRoute.png

Then go to the document Properties -> URLs tab and add additional document alias configured as shown in this picture:

RazorAlias.png

The alias will provide us with a nice wildcard URL to the detail of particular news.

Now if I see the page output, I get a nice clean view provided by the Razor MVC view engine. That was easy, right?

RazorLive.png

I hope you enjoyed this demonstration. Should you need any further information, do not hesitate to ask me in the comments.

See you next time ...

Share this article on   LinkedIn

Martin Hejtmanek

Hi, I am the CTO of Kentico and I will be constantly providing you the information about current development process and other interesting technical things you might want to know about Kentico.

Comments

Martin Hejtmanek commented on

Hi Manoj,

If you use web forms as the view model, you can simply use Kentico CMS components to render the content, see the default examples on our sample Corporate site, they are using master pages. However the whole point of MVC is to COMPLETELY separate business logic from presentation, so solution like that is not really "by the book", and you may not be able to create solution on which you can run automated tests, which is one of the main MVC points. Alternatively, you can use partial views and layouts as shown in the example above, but you should still feed all the page data from the controller.

Manoj Shah commented on

Hi,

Is there any way to get content from existing master page templates to render around the mvc area. e.g. get the menu, header and footer via Kentico, rather then code inside the mvc template?

Thanks
Manoj

Manoj Shah commented on

Thanks this is a great blog post.