Extend the Razor view engine, MVC 3

I come cross a project that integrated a CMS publishing system into a MVC web application. The CMS content is published into an application folder. We don’t publish them into the View folder, or any of the MVC folders (controllers, models, content, etc.) is because we need to give write permission to the targeted folder. Due to the security reason, it is a better idea to publish to a particular folder and using our custom view engine to let controllers render them correctly.

Here I created a sample application for the demonstration purpose.

1. I create a folder call “StaticContent”, and we assume the CMS will publish contents to this folder. Then I created a few content files, like 101.cshtml, 102.cshtml, 103.cshtml.

image

Here you may notice, there are two files included in the folder, _ViewStart.cshtml and Web.config.

Because we want to make sure all the views in StaticContent folder are using the same layout. I copied the _ViewStart.cshtml file from “Views” folder into this folder. So when the controller will use the same _Layout.cshtml to render these views.

The web.config is copied from “Views” folder as well. Basically the purpose is to prevent access to your views by any means other than the controllers.

2. Create a “StaticPageViewEngine” class to implement RazorViewEngine

	public class StaticPageViewEngine : RazorViewEngine
	{
		public StaticPageViewEngine()
		{
base.ViewLocationFormats = base.ViewLocationFormats.Concat(new string[] { "~/StaticContent/{0}.cshtml" }).ToArray();
		}
	}

In the constructor, add the new location of the views in ViewLocationFormats. It is a string[], by default it has 4 values, after we added the new location, it becomes 5.

image

3. Next step is to register this view engine in Application_Start() in Global.asax.

protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();

RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);

ViewEngines.Engines.Add(new StaticPageViewEngine());

}

4. Create a controller and action method to render the views. And you can test it by going to “/Home/Test001”

public ActionResult Test001()
{
return View("101");
}

5. To make it dynamically rendered by a controller action method, we can register a special route in Global.asax

Global.asax

public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

// Static page
routes.MapRoute(
"Page", // Route name
"Page/{viewName}", // URL with parameters
new { lang = "en", controller = "Home", action = "StaticDetail" } // Parameter defaults
);

routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);

}

Controller method,

public class HomeController : Controller
{
//
// GET: /Home/

public ActionResult Index()
{
return View();
}

public ActionResult Test001()
{
return View("101");
}

public ActionResult StaticDetail(string viewName)
{

return View(viewName);

}
}

And it is all done. You can test all the static content views by using route “/Page/101”, “/Page/102”, etc.

The Sample source code can be downloaded from google code: https://extending-razor-view-engine.googlecode.com/svn/trunk/

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s