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'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'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:
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.
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.
Then go to the document Properties -> URLs tab and add additional document alias configured as shown in this picture:
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?
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 ...