When you design a modular ASP.NET application, soon or later you will need to think about adding extensibility features to your project so that it will be possible to add new modules at runtime. There are a few architectures and designs that let you develop an extensible application, like ASP.NET MVP. However, many of them add a lot of complexity almost to everything and one should learn many concepts to use them. Therefore, it’s a good idea to use other simple but innovative methods like the one I will explain bellow.
The method I am going to mention lets you develop an ASP.NET application and add some more modules to it later at runtime. In a nutshell, it has the following benefits:
- Allows adding new pages to an existing web application at runtime and does not need any recompilation.
- Allows adding new web parts to an existing content management system (Portal) at run-time.
- Several developers can develop different parts of an application.
- It is very easy to understand, develop and use.
- Does not exploit any 3rd party library so nothing is needed except Visual Studio.
And it has the following drawbacks:
- One should know the exact structure of an existing ASP.NET application, like folder hierarchies.
- May not cover all possible scenarios (Actually I have not taught about many scenarios).
How to implement it?
The design I am going to explain is possible only if you develop an ASP.NET Web Project rather than an ASP.NET web site. As far as I remember, visual studio 2005 does not let you create a web project. If I am right, you need to use Visual Studio 2008. However, there are two main parts that we need to develop:
- A web application project that includes main modules, main pages, and loads plugged modules, checks licensing, perform security tasks etc.
- Plugged modules, which will add more pages, web parts and functionalities.
Main application and modules must match. It means that they must have same structure (i.e. folders), use same master pages and follow same rules.
The main reason that I used a Web Application Project, rather than a Web Site, was the benefits of a Web Application Project for developing a plug-in based web site. After building a web application project, there will be one assembly and several .aspx, .ascx, .ashx … files. After the web application is published, there is possibility to add more pages and files to it. Therefore, if at a later time we add several .aspx pages along with their .dll files, the web application will be able to work with those pages with no problem.
When developing the main application, you should consider a well formed directory structure, language specific contents, master pages etc. For example, your application should have a master page with a general name, like Site.Master. It also needs to maintain each module’s pages in a separate folder so that new modules can follow the same rule and avoid naming conflicts etc.
To develop the main application, follow the steps bellow:
- Create an empty solution in VS 2008.
- Add a new ASP.NET Web Project (not a web site) to the solution.
- Add any required folders like App_Themes and implement any required authentication, authorization and personalization mechanisms. Your web application must be complete and working.
- Add a master page to the web application project and name it Site.Master or another general name.
- Add a new Class Library Project and call it Framework (i.e. mycompany.myproject.Framework), common or whatever name that indicates this class library will be shared between the main application and dynamic modules.
- Add a new interface to the mentioned class library and call it IModuleInfo. This interface will be implemented with a class inside any pluggable module and will return root menu items that must be added to main application’s menu (or items to be added to a site navigation). It also can return a list of WebParts that introduces web parts that exist inside the module.
public interface IModuleInfo
{
List<MenuItem> GetRootMenuItems(string[] UserRoles);
}
UserRoles parameter is not mandatory. It shows that you can pass parameters to the method that returns a module’s main menu items. In this example, it indicates which Roles the current user has so that menu items will be filtered properly.
- Add a new ASP.NET Web Application project to the solution and name it SampleModule.
- Add a folder called SampleModule and if necessary, add more sub-folders.
- Add a web.config file to SampleModule folder and define which users/roles can access which folder.
- Add a master page named Site.Master. In fact , it must have same name with your master page in the main application.
- Add a public class with any name (I call it ModulePresenter) that implements IModuleInfo (this interface was added to Common or Framework library).
ModulePresnter class will return a list me menu items to main application. Main application will add those menu items as root items to its main menu afterwards. I will not bring a detailed code for the part that a module creates these items; it is dependent on your project.
public class ModulePresenter : IModuleInfo
{
#region IModuleInfo Members
public List<System.Web.UI.WebControls.MenuItem> GetRootMenuItems(string[] UserRoles)
{
List<MenuItem> items = new List<MenuItem>();
//:
//:
return items;
}
#endregion
}
- Compile this application and go back to the main application.
- Add an XML file and call it PluggedModules.xml. This file maintains the qualified type name of each module that must be loaded. A qualified type name includes assembly, namespace and class name
<?xml version=”1.0″ encoding=”utf-8″ ?>
<modules>
<module name=”SampleModule” type=” SampleModule.ModulePresenter, SampleModule.dll”></module>
</modules>
- Write a code to query PluggbedModules.xml, get menu items and attach them to main menu:
public static void LoadModules(Menu menuControl , string[] userRoles, string xmlName)
{
XDocument document = XDocument.Load(HttpContext.Current.Server.MapPath(string.Format(”~/{0}” , xmlName)));
var allModules = document.Elements(”modules”);
foreach(XElement module in allModules.Elements())
{
string type = module.Attribute(”type”).Value;
IModuleInfo moduleInfo = Activator.CreateInstance(Type.GetType(type)) as IModuleInfo;
List<MenuItem> allItems = moduleInfo.GetRootMenuItems(userRoles);
foreach(MenuItem item in allItems)
{
menuControl.Items.Add(item);
}
}
}
As seen in the above code, we query PluggedModule.xml file , extract introduced files and create an instance of it using Activator.CreateInstance method. Then extract IModuleInfo implementation, call GetRootMenuItems to get module’s menu items and add it to main menu.
After doing all the above steps, copy modules .dll file (generated after you build the project) to main application’s \bin folder and add it’s main folder (SampleModule) to main application’s root folder. It will work fine until all naming matches (for example both use master pages with a same name) and when specifying target URL in menu items, they point to a relative path, i.e. SampleModule/MyPage.aspx.
Please download the sample code from here.








By clicking on OK button, Windows Media Encoder begins and Properties window is seen. If not, click on “Properties” button on toolbar. In this place, for Video, choose Screeen Capture. You can click on Configure button and tell Windows Media Encoder how to capture your computer screen. Available options are: Entire Screen, Region or Window.




