Create Orchard Module in a Separate Project

The Orchard Project is a new OOS Microsoft project that is being developed up on CodePlex. From the Orchard home page on CodePlex, it states

"Orchard project is focused on delivering a .NET-based CMS application that will allow users to rapidly create content-driven Websites, and an extensibility framework that will allow developers and customizers to provide additional functionality through modules and themes."

The Orchard Project site contains additional information including documentation and walkthroughs. The ability to create a composite solution based on a collection of modules is a compelling feature. In Orchard, these modules can just be created as simple MVC Areas or they can also be created inside of stand-alone web application projects.  The walkthrough for writing an Orchard module that is available on the Orchard site uses a simple Area that is created inside of the host application. It is based on the Orchard MIX presentation. This walkthrough does an effective job introducing various Orchard concepts such as hooking into the navigation system, theme/layout system, content types, and more.  However, creating an Orchard module in a separate project does not seem to be concisely documented anywhere. Orchard ships with several module OOTB that are in separate assemblies – but again, it's not well documented how to get started building one from scratch.

The following are the steps I took to successfully get an Orchard module in a separate project up and running.

Step 1 – Download the OrchardIIS.zip file from the Orchard Release page. Unzip and open up the solution.

*_Step 2_ *– Add your project to the solution. I named my project "Orchard.Widget" and used and "MVC 2 Empty Web Application" project type. Make sure you put the physical path inside the "Modules" sub-folder to the main project like this:

At this point the solution should look like:

Step 3 – Add assembly references to Orchard.dll and Orchard.Core.dll.

Step 4 – Add a controller and view.  I'll just create a Hello World controller and view. Notice I created the view as a partial view (*.ascx). Also add the [Themed] attribute to the top of the HomeController class just like the normal Orchard walk through shows it.

Step 5 – Add Module.txt to the project root. The is a very important step. Orchard will not recognize your module without this text file present.  It can contain just the name of your module: name: Widget

Step 6 – Add Routes.cs. Notice I've given an area name of "Orchard.Widget" on lines 26 and 33.

  
using System;  
using System.Collections.Generic;  
using System.Web.Mvc;  
using System.Web.Routing;  
using Orchard.Mvc.Routes;  
 
namespace Orchard.Widget  
{
    public class Routes : IRouteProvider
    {
        public void GetRoutes(ICollection<RouteDescriptor> routes)
        {
            foreach (var routeDescriptor in GetRoutes())
            {
                routes.Add(routeDescriptor);
            }
        }
 
        public IEnumerable<RouteDescriptor> GetRoutes()
        {
            return new[] {
                new RouteDescriptor {
                   Route = new Route(
                       "Widget/{controller}/{action}/{id}",
                       new RouteValueDictionary {
                           {"area", "Orchard.Widget"},
                           {"controller", "Home"},
                           {"action", "Index"},
                           {"id", ""}
                       },
                         new RouteValueDictionary(),
                         new RouteValueDictionary {
                             {"area", "Orchard.Widget"}
                         },
                         new MvcRouteHandler())
                }
            };
        }
    }
}

Step 7 – Add MainMenu.cs. This will make sure that an item appears in the main menu called "Widget" which points to the module.

  
using System;  
using Orchard.UI.Navigation;  
 
namespace Orchard.Widget  
{
    public class MainMenu : INavigationProvider
    {
        public void GetNavigation(NavigationBuilder builder)
        {
            builder.Add(menu => menu.Add("Widget", item => item.Action("Index", "Home", new
            {
                area = "Orchard.Widget"
            })));
        }
 
        public string MenuName
        {
            get { return "main"; }
        }
    }
}

Step 8 – Clean up web.config. By default Visual Studio adds numerous sections to the web.config. The sections that can be removed are: appSettings, connectionStrings, authentication, membership, profile, and roleManager.

Step 9 – Delete Global.asax. This project will ultimately be running from inside the Orchard host so this "sub-site" should not have its own Global.asax.

Now you're ready the run the app.  When you first run it, the "Widget" menu item will appear in the main menu because of the MainMenu.cs file we added:

We can then click the "Widget" link in the main menu to send us over to our view:

From start to finish, it's a relatively painless experience but it could be better. For example, a Visual Studio project template that encapsulates aspects from this blog post would definitely make it a lot easier to get up and running with creating an Orchard module.  Another aspect I found interesting is that if you read the first paragraph of the walkthrough, it says,

"You can also develop modules as separate projects, to be packaged and shared with other users of Orchard CMS (the packaging story is still to be defined, along with marketplaces for sharing modules)."

In particular, I will be extremely curious to see how the "packaging story" evolves. The first thing that comes to mind for me is: what if we explored MvcContrib Portable Areas as a potential mechanism for this packaging? This would certainly make things easy since all artifacts (aspx, aspx, images, css, javascript) are all wrapped up into a single assembly. Granted, Orchard does have its own infrastructure for layouts and themes but it seems like integrating portable areas into this pipeline would not be a difficult undertaking. Maybe that'll be the next research task. :)