Building DotNetNuke Modules Using Razor
12/6/2010 1:55 PM
In Occam’s Razor and DotNetNuke, I showed you how to create a Razor script that you can run using the DotNetNuke Razor Host module. This is great for simple scripts. One of the downsides of scripts is that Scripts don’t have packaging and installation support. If you want to re-use the script, or allow others to re-use the script, then you will have to provide manual installation steps for the scripts.
For more complex solutions or those which I want to re-deploy on another site, I will want to package my script as a DotNetNuke module. Future versions of the Razor Host module will automate this for me, but for now I’ll need to do this by hand. It’s not really all that difficult, and in this post I’ll show you how to accomplish this for your scripts.
In my first post, a user asked me how hard it would be to add a role selector, so in addition to packaging up my script as a module, I’ll also add this feature. One of the main purposes of modules is to re-use functionality on multiple sites. This often requires some configuration of the script to make it usable for many different sites which may be configured differently. For example, in my original script, I was listing out the users in the “CoreTeam” role, however, other sites may want to list users in a different role.
“Genericizing” My Script
To make my script more generic, and thus more useful to other users, I’ll want to remove the hardcoded role name and instead provide a method to select a role name and display the associated users. In my scenario, I am going to add a simple dropdown list that allows the user to select the users to display based on the role selected. You could also choose to use a role name filter like that used on the Role management or user management page in DotNetNuke, but I’ll leave that as an exercise for the reader.
To use the dropdown, I need to add some code to get the list of roles available in DotNetNuke. When I perform the postback from the “refresh” button, I’ll need to use the dropdown list value to get the list of users in the associated role. Also, since I am converting my script to a standalone module, I’ll want to use an images directory in my module directory to get the images I use for the background and for the social networking icons. One additional item I want to point out is the use of the VirtualPath property which provides the directory where the script is located. In the final version of the DotNetNuke Razor API, we’ll add a property that is similar to the ControlPath property that is currently used in DotNetNuke modules. With all these changes made, I now have the following code, which is not much different than the code in my original script:
var teamImageDir = Href(Dnn.Portal.HomeDirectory) + "teamImages";
var users = (new RoleController()).GetUsersByRoleName(Dnn.Portal.PortalId, "Coreteam");
var teamImageDir = Href(VirtualPath) + "/Images";
var roleCntlr = new RoleController();
var users = roleCntlr.GetUsersByRoleName(Dnn.Portal.PortalId,
"Administrators" : Request["displayRole"]));
var arrRoles = roleCntlr.GetPortalRoles(Dnn.Portal.PortalId);
The only additional change I need to make to my code is to actually create the dropdown list and bind it to the list of roles I retrieved in the code above.
At this point I now have the ability to select the role I want, hit the refresh button, and my page will update to display just those users who are a member of that role.
Packaging My Module
The heart of every DotNetNuke Module is some type of Control. It can be a user control (.ascx) or a web control compiled into an assembly. In both cases, the core framework is able to load the control and rely on the Asp.Net Webforms engine to run the code necessary to render our application. Since Razor modules need to be able to run in the existing DotNetNuke release which is unaware of the Razor view engine, we needed a technique to bootstrap the Razor script. This function is already handled by the Razor Host module, but since we are building a standalone module we won’t really have the razor host module available to us. Instead, what we do is create a dummy .ascx file that inherits from RazorModuleBase.
<%@ Control AutoEventWireup="false" Inherits="DotNetNuke.Web.Razor.RazorModuleBase" %>
This ascx file must be named with the same name as the underlying cshtml or vbhtml script, very similar to the way that ascx files and codebehind files share a standard naming convention. In this case, since my script is named _ContactList.cshtml, my ascx file will be named ContactList.ascx. It should go without saying that I need to have these files in the same directory. This ascx gives me the needed hook that I can use when registering a ModuleControl. The RazorModuleBase class knows how to render and execute the associated script file, without involving any changes to the core DotNetNuke platform.
The last step for creating my Razor module is to create the needed module manifest file. In order to keep my module size as small as possible I make it dependent on the Razor Host module being installed first. This makes sure that all of the necessary assemblies are already installed and helps prevent DLL hell with different modules installing different versions of the WebMatrix and Razor assemblies.
Razor Contact List
You can download the updated Razor Contact List module on Codeplex.