The Community Blog is a personal opinion of community members and by no means the official standpoint of DNN Corp or DNN Platform. This is a place to express personal thoughts about DNNPlatform, the community and its ecosystem. Do you have useful information that you would like to share with the DNN Community in a featured article or blog? If so, please contact [email protected].

WebMatrix and DNN – 5 – Hosting the Razor Engine

In my previous post in this series on the new WebMatrix suite of technologies from Microsoft, I described how we are supporting the use of Razor scripts in DotNetNuke, by providing a “Razor Host” module. In this article I will dive deeper into how we host the Razor Parser.

Razor can actually be thought of as a templating engine and if you are planning on building a module that requires templates you might want to consider Razor. Hopefully, this article will show how you might do that.

The WebPage Class

The WebPage Class (actually WebPageBase) is the basis of the new WebPages Framework, in the same way that the “Page” class is the basis of the WebForms Framework.

Essentially the approach we use in our “Razor Host” module is as follows.

Identify the Razor script file (e.g. Twitter.cshtml)

Call BuildManager.GetType(scriptFile) to create an instance of WebPage. Note that the System.Web.WebPages assembly contains a special class – PreApplicationStartCode – that ensures that the extensions cshtml and vbhtml are registered with the BuildManager

Call the ExecutePageHierarchy method of the WebPage class and capture the rendered content.

Create a LiteralControl with the rendered content and add it to the control tree.

In order to achieve this there are two new classes in a new assembly (DotNetNuke.Web.Razor.dll) which is distributed as part of the “Razor Host” Module.

The RazorModuleBase Class

The RazorModuleBase class is where everything comes together. All DNN Modules need to implement the IModuleControl Interface – this how the module injection logic knows what to inject. RazorModuleBase is a new base class that implements IModuleControl and is used as the base class for the Razor Host Module.

In the OnPreRender method of the class we first check if our script - RazorScriptFile – exists. If it does we call the CreateWebPageInstance method to get an instance of the DotNetNukeWebPage (lines 7-16)

We then set the WebPage’s module context by calling its SetContext method (line 26). This allows us to access the ModuleContext in Razor script. Finally we call the WebPage’s ExecutePageHierarchy method to get the rendered content, which we add as a LiteralControl to the Controls collection of the module.

In the above description I glossed over two important points: the RazorScriptFile property and the CreateWebPageInstance property.

The RazorScriptFile property (Figure 2) returns the virtual path of a “default” script file. In the Razor Host module, we override this property and return the currently selected script, but the default behaviour in the base class is to return “MyScript.cshtml” if the current control is “MyScript.ascx”.

Figure 2 - The RazorScriptFile property

1: ProtectedOverridableReadOnlyProperty RazorScriptFile AsString

2: Get

3: ReturnMe.AppRelativeVirtualPath.Replace("ascx", "cshtml")

4: EndGet

5: End Property

The CreateWebPageInstance method (Figure 3) uses the RazorScritpFile property to create an instance of a DotNetNukeWebPage (Figure 3), calling BuildManager.GetCompiledType (line 2), which returns a Type and then calling Activator.CreateInstance (line6) to return an instance of the DotNetNukeWebPage.

Figure 3 – CreateWebPageInstance

1: PrivateFunction CreateWebPageInstance() AsObject

2: Dim type As Type = BuildManager.GetCompiledType(RazorScriptFile)

3: Dim instance AsObject = Nothing

4:

5: If type IsNot NothingThen

6: instance = Activator.CreateInstance(type)

7: EndIf

8:

9: Return instance

10: End Function

Earlier in this article I mentioned that BuildManager knew to “build” a WebPage instance from a cshtml or vbhtml because of some code that exists in the WebPages Framework that registers the extension. So why do we get an instance of DotNetNukeWebPage rather than an instance of WebPage?

The answer lies in the included web.config file that sits in the same folder as the Razor Host Module. By default the Razor Engine will return an instance of WebPage, but this can be modified in the new system.web.webPages.razor section of web.config, where we have indicated that an instance of DotNetNukeWebPage should be returned.

Figure 4 – Razor Host Module’s web.config file

1: <system.web.webPages.razor>

2: <pagespageBaseType="DotNetNuke.Web.Razor.DotNetNukeWebPage">

3: <namespaces>

4: <addnamespace="Microsoft.Web.Helpers"/>

5: <addnamespace="WebMatrix.Data"/>

6: namespaces>

7: pages>

8: system.web.webPages.razor>

At the moment we are just including this web.config file as part of the module, but in the final release we will probably update the web.config file in the website root to include the information.

So that was for all the Architect types who want to know how it was done. In the next blog I will show how you can “package” up a script you have created and distribute it to other DNN users.

Content Layout

Subscribe to DNN Digest

Subscribe to DNN Digest

DNN Digest is our monthly email newsletter. It highlights news and content from around the DNN ecosystem, such as new modules and themes, messages from leadership, blog posts and notable tweets. Keep your finger on the pulse of the ecosystem by subscribing.