Building DotNetNuke Modules Using Razor

Dec 6

Written by: Joe Brinkman
12/6/2010 1:55 PM  RssIcon

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.

dropdownlist

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:

Original:

@{ 
  var teamImageDir = Href(Dnn.Portal.HomeDirectory) + "teamImages";
  var users = (new RoleController()).GetUsersByRoleName(Dnn.Portal.PortalId, "Coreteam");
}

Updated:

@{   
  var teamImageDir = Href(VirtualPath) + "/Images";
  var roleCntlr = new RoleController();
  var users = roleCntlr.GetUsersByRoleName(Dnn.Portal.PortalId, 
	((Request["displayRole"].IsEmpty()) ? 
	  "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 ContactList
  
  
    DotNetNuke
    DotNetNuke Corporation
    www.dotnetnuke.com
    joe@dnncorp.com
  
  
  
  
    05.06.00
    System.Tuple
    DotNetNuke.Web.Razor.RazorModuleBase
  
  
    
      
        RazorModules.ContactList
        RazorModules/ContactList
        
        
        
          
            Razor Contact List
            0
            
              
                
                DesktopModules/RazorModules/ContactList/ContactList.ascx
                False
                
                View
                
                
                0
              
            
          
        
      
    
    
      
        DesktopModules\RazorModules\ContactList
        
          ContactList.ascx
        
        
          _ContactList.cshtml
        
        
          module.css
        
      
    
    
      
        DesktopModules\RazorModules\ContactList\images
        
          FB.png
          images
        
        
          LI.png
          images
        
        
          TW.png
          images
        
        
          topbg.png
          images
        
      
    
  

You can download the updated Razor Contact List module on Codeplex.

dummy