You can use modules to encapsulate a set of concerns of your application and independently deploy them to your applications. The Composite Web Application Block distinguishes between two types of modules:
- Foundational modules. A foundational module does not contain Web pages. The primary purpose of a foundational module is to provide services to the other modules in the application. For example, a foundational module can contain code that provides
instrumentation, such as logging.
- Business modules. A business module can contain any of the application classes required by the concerns that the module encapsulates.
Figure 1 illustrates typical objects organized by application layer (a module can contain all, or some combination, of the listed components).
There are three types of files that comprise a module's deployment unit:
- Module Web pages. These are the ASP.NET Web pages displayed for your module. (Only business modules contain Web pages.)
- Module assembly. This is a class library that contains the logic for your module.
- Web.config file. This is an ASP.NET configuration file. The application block uses this file to identify the module assembly and the location of the Web pages. A module can have a separate Web.config file, or you can add the entries required for
a module to the Web site Web.config file.
When your Web client application starts, the Composite Web Application Block locates the Web.config files in the Web site and looks for a configuration section that contains module information. The application block uses this information to load module assemblies.
You can specify module information in the Web.config file for the Web site, or you can create a module-specific Web.config file in the module's Web site folder.
You can create a module that does not include any Web pages. For example, you can create a module that contains only services that are used by other modules.
illustrates different deployment examples.
Module deployment units
The following describes the modules illustrated in the preceding figure:
- Module A is a foundational module and does not contain any Web pages. The Web site Web.config file contains the module information. The Web site does not contain a folder for the module (it does not require one because the module does not have Web pages
or a Web.config file).
- Module B is a business module. The Web pages reside in a Web site folder specific to Module B. The module folder contains a Web.config file for the module.
- Module C is a business module and its Web pages reside in a folder specific to that module. The module folder contains a Web.config file for the module.
You can XCopy deploy a module to a Web site. This means you can independently deploy modules in an application.
Module Web Pages
Typically, business modules contain visual representations of data, such as a Web part, Web server control, user control, or Web pages. (A module that does not contain any visual components; instead, it contains services that are used by other modules is known
as a foundational module.)
You can use the Composite Web Application Block to easily create Web client applications that are composed of Web pages that exist in different modules. The application block does not contain explicit support for creating Web pages composed of user interface
elements contained within different modules. Composability within a Web page is a technical challenge that is to be addressed is a future release.
Module Web pages can use either the single-file page model or the ASP.NET code-behind page model. Code-behind pages offer a clean separation of the markup (user interface) and code. With this model, it is practical to have a designer working on the markup while
a programmer writes code. (For information about ASP.NET page models, see
ASP.NET Web Page Code Model
A module assembly includes the logic for the application concerns encapsulated by the module. This can include the logic for handling user interaction events and presentation. A module assembly can contain classes for services. A service can be specific to
the module (the module adds it to the module's composition container) or global to all modules (the module adds it to the root composition container).
Module Loading and the IModuleInitializer Interface
During application startup, the application block discovers all Web.config files located in the Web site folder hierarchy. It uses the information in the files to identify and load module assemblies.
A module initialization class is a class that implements the IModuleInitializer
interface. This class contains initialization code that runs when the Composite Web Application Block loads the module. This interface defines two methods,
. You implement these methods to perform module initialization tasks, such as registering services or adding site map nodes to the site map.
public interface IModuleInitializer
void Load(CompositionContainer container);
void Configure(IServiceCollection service, System.Configuration.Configuration moduleConfiguration);
When loading modules, a Composite Web Application Block service (ModuleLoaderService
) reflects on the module assembly and looks for a class that implements the
interface. When the module assembly contains a class that implements this interface, the application block dynamically instantiates the class and executes its
methods. Figure 3
illustrates key classes and events for module loading.
Module loading and initialization
The following list describes the numbered elements in the preceding figure:
- The Global.asax file specifies WebClientApplication as the application class.
- ASP.NET calls the Application_Start method of the WebClientApplication class.
- The WebModuleEnumeratorService creates information for the modules in the Web site. To do this, it calls the
- The WebConfigModuleInfoStoreService locates all Web.config files in the Web site directory structure.
- The WebConfigModuleInfoStoreService service looks for module definition information in the Web.config files.
- The WebClientApplication passes the module information to the ModuleLoaderService service.
- The ModuleLoaderService loads each module and calls the module for initialization.
When the ModuleLoaderService
service loads a module, it creates a new CompositionContainer
object for the module. You can use this composition container to store components (for example, services) that you do not want to share with other modules
of the application. Your module can access this composition container through the
parameter of the Load
The Composite Web Application Block provides a base class (ModuleInitializer
) that implements the
interface. You can use this class as the base class for your own module initialization classes. The
class contains the following virtual methods that you can override:
- Load. The implementation of this method invokes the AddGlobalServices and
AddModuleServices methods. You can override this method to execute custom module initialization code.
- Configure. The implementation retrieves authorization rules from the configuration information and registers the rules with the
IAuthorizationRulesService service. Override this service to use additional configuration information.
View Interfaces and Presenters
If the module contains Web pages (deployed as .aspx files in the Web site), user controls, or a master page, and you choose to implement the View-Presenter pattern, the module assembly will also contain the following:
Is the View-Presenter pattern right for your application?
- View interface definitions. The code-behind class of each Web page or user control implements an interface for that view.
- Presenters. Each view is associated with a presenter. The presenter contains the user interface logic.
The application block does not require you to use the View-Presenter pattern. The View-Presenter pattern requires an additional interface definition and presenter class for every view (Web page, master page, or user control).
The Composite Web Application Block contains the abstract generic class Presenter<T>
, where T is a view interface type. You can use this class to implement the View-Presenter pattern. In this pattern, the presenter contains a reference to the view
interface; it does not include a reference to the view implementation (the code-behind class). This means you can use a mock implementation of the view (one that implements the view interface) to test the presenter. To use this class, you derive your presenter
from the generic Presenter<T>
class, as illustrated in the following code (taken from the Modularity QuickStart).
public class SummaryViewPresenter : Presenter<ISummaryView>
// Presenter implementation
The Presenter class declares two virtual methods:
- OnViewInitialized. This method is invoked by the view the first time it loads.
- OnViewLoaded. This method is invoked by the view every time it loads.
The common view implementation of this pattern includes code similar to the following in the
method of a view that has a presenter.
protected void Page_Load(object sender, EventArgs e)
When you deploy a module, you copy the module assembly to the bin folder and copy the module's Web pages and Web.config file to a folder in the Web site. You must add information to the module’s Web.config file that specifies the name of the module assembly
and the location (a folder path relative to the Web site root) of the module's Web pages.
Alternatively, you can add the module information to the Web site Web.config file. When you do this, the Web site Web.config file acts a centralized module information store, and you cannot XCopy deploy your module (deployment with a centralized module information
file requires you to modify the Web site Web.config file at deployment time).
You must place the module information file in the folder hierarchy of the Web site. The
service recursively searches for Web.config files in the Web site folder hierarchy. This service reads the module configuration information, and the
service uses this information to load the module assembly.
The following XML shows the content of the modules configuration section for the
<module name="Shell" assemblyName="ModularityQuickstart.Shell" virtualPath="~/"/>
<module name="Navigation" assemblyName="ModularityQuickstart.Navigation"/>
You can express module dependencies in the module configuration section. For example, the Modularity QuickStart has three modules, Shell, Navigation and Customers. The Customers module information file contains a
XML element. This element defines a dependency on the Shell and Navigation modules. This means that the application block will load the Infrastructure module before it loads the Customers module.
<module name="Customers" assemblyName="ModularityQuickstart.Customers" virtualPath="~/Customers">
<dependency module="Shell" />
<dependency module="Navigation" />