Behind the Configuration Design-Time


The Enterprise Library Configuration Tool is really just a Windows Form application that uses the design-time features in the Configuration Application Block. The Configuration Application Block's design-time features are based on the same concepts and architecture as the design-time features for .NET Windows Forms and ASP.NET applications: the classes in the System.ComponentModel namespace. Exposing the Configuration Application Block's design-time features has many benefits. It provides a single, consistent model that all application blocks can use to display, validate, and update the configuration data for their runtime components. It also gives you design-time configuration capabilities for adding your own StorageProviders, Transformers, application blocks, and extensions to application blocks.

Figure 2.17 depicts several concepts. First, it illustrates how the Enterprise Library Configuration Tool uses the design-time features in the Configuration Application Block to achieve its needs. It also emphasizes that the Configuration Application Block's design-time objects rely on its runtime objects for saving and retrieving configuration information. Lastly, it shows how client applications that are built to use Enterprise Library will either directly or indirectly use the Configuration Application Block's runtime features for storing and retrieving either their own custom configuration information or the configuration information needed for the Enterprise Library application blocks to function properly.

Figure 2.17. High-Level Design of the Configuration Application Block's Design-Time


The following sections describe the concepts behind the Configuration Application Block's design-time and how it uses the classes contained in the System.ComponentModel namespace. They include a discussion of how you can use the design-time features in the Configuration Application Block to provide new design-time features in the Enterprise Library Configuration Tool and walks you through an example of creating such an extension.

Using the System.ComponentModel Namespace

Enterprise Library's Configuration design-time is based heavily on the .NET System.ComponentModel namespace. This namespace includes base classes and interfaces for implementing attributes and type converters, binding to data sources, licensing components, and more. The namespace provides Enterprise Library with a valuable service-based model that is not only used to implement its runtime and design-time behavior for components and controls, but it also allows Enterprise Library's design-time experience to be extended. Some of the interfaces used by the Enterprise Library Configuration design-time are IComponent, IContainer, ISite, IServiceProvider, and IServiceContainer.

The IComponent Interface

The IComponent interface defines the functionality that must exist for all components. The System.ComponentModel.Component class is the default implementation of this interface and is the base class for all components in the common language runtime that marshal by reference. Components are especially important because they can access services from a container that owns the component. In Enterprise Library, the abstract Configuration-Node classand therefore any class that derives from Configuration-Nodeis a component. Figure 218 illustrates how the ConfigurationNode class derives indirectly from System.ComponentModel.Component and shows just a few of the concrete ConfigurationNode classes (e.g., XmlIncludeTypeNode, StorageProviderNode, TransformerNode, and ApplicationConfigurationNode) that derive from this base class.

Figure 2.18. ConfigurationNode Derives From Component


Configuration nodes provide the design-time representation of configuration settings and do the following.

  • Determine how the Enterprise Library Configuration Tool will display the hierarchy of configuration settings

  • Control which properties are exposed in the graphical interface

  • Enable the validation for the values a user assigns to a configuration node

  • Contain references to the runtime data classes

The left pane of the Enterprise Library Configuration Tool displays the configuration nodes in a configuration tree (see Figure 2.19). When a user selects a configuration node, the collection of settings associated with that configuration node display in the Property pane.

Figure 2.19. Configuration Nodes and the Property Pane


When an application's configuration is created or opened, the Enterprise Library Configuration Tool first creates an application configuration node and adds it to the SolutionConfigurationNode, the top-level node to which all other nodes are attached. The SolutionConfigurationNode is always named Enterprise Library Configuration.

The application configuration node is the parent for all application block nodes that are added to that application's configuration. Child nodes underneath the application node are associated with application blocks. Figure 2.19 shows an application that is configured to use the Data Access Application Block; therefore, the application node is the node labeled Application1 and the Data Access Application Block is a child node. Because all application blocks depend on the Configuration Application Block, a node for the Configuration Application Block also appears as a child to the application node.

Configuration nodes have properties that allow them to be maintained in parent-child relationships with other nodes. Each node can have at most one parent node, but it can have multiple child nodes. The parent-child relationship of nodes allows configuration settings to be organized in a logical hierarchy at design time. The Enterprise Library Configuration Tool uses this hierarchical relationship to construct the configuration tree.

All configuration nodes derive from the abstract ConfigurationNode base class. A ConfigurationNode's public properties are exposed and editable at design time as properties displayed within the node's Property pane. In Figure 2.19, the DatabaseInstance node is referencing a DatabaseType node and a ConnectionString node. Clicking the plus sign next to the node's settings will let you edit the settings for the node. The Name property is also exposed and editable for this node. Every configuration node includes the public property Name, which represents the name of the node that is displayed in the tree view.

The IContainer Interface

The System.ComponentModel.IContainer interface defines the functionality that must exist for a container, an object that encapsulates and tracks zero or more components. The IContainer interface defines the properties and methods that must exist to wrap around a collection of components. The Components property returns a ComponentsCollection; the Add and Remove methods allow components to be added to and removed from the collection.

The Container class is the default implementation of the IContainer interface. In addition to the Components property and the Add and Remove methods, the Container class also provides a CreateSite method for creating a Site (explained next) for a given component in the container, and a GetService method for retrieving a service object for a specified type. By using a container in an application, application-wide services can be retrieved throughout the entire application. In Enterprise Library, the ConfigurationDesignHost class implements the IContainer interface and is the container for all the classes that derive from ConfigurationNode. Figure 2.20 shows the ConfigurationDesignHost's properties and methods.

Figure 2.20. Properties and Methods of ConfigurationDesignHost


The ISite Interface

A site "glues" a component to the container it lives in and enables communication between the two. The ISite interface defines the properties needed to enable service retrieval by a component. In Enterprise Library, the ConfigurationNodeSite class implements the ISite interface. It binds configuration nodes with the ConfigurationDesignHost. Figure 2.21 shows the properties and methods for the ConfigurationNodeSite. Two notable properties are the Component and Container properties; these are used to bind the two together.

Figure 2.21. Properties and Methods of ConfigurationNodeSite


The IServiceProvider and IServiceContainer Interfaces

The IServiceProvider and IServiceContainer interfaces derive from the System namespace. A service object is an object that provides custom support to other objects. Services are powerful because they allow for a loose coupling between the interface that defines a service and the classes that implement it. Components can request a service and retrieve an instance that they can use, but they never need to know anything about the implementation of the service.

The IServiceProvider interface defines a mechanism for retrieving a service object. A service container is, by definition, a service provider. In addition to providing services, it also provides a mechanism for adding and removing services. To obtain a service at design time, the GetService method of a component sited in design mode can be called.

Designers and other objects can add or remove services at design time as well. When a service is added, it can be added with instructions to promote it. When a service is promoted, it is added to all parent service containers until the top of the service container tree is reached. This allows a designer to provide a global service that other objects in the process can use.

Enterprise Library's abstract ServiceContainer class implements both the IServiceContainer and IServiceProvider interfaces. The ConfigurationDesignHost derives from the ServiceContainer class; thus, it is also a ServiceContainer. Figure 2.22 shows the ServiceContainer's methods. Notice the methods that exist for adding, getting, and removing services.

Figure 2.22. Properties and Methods of ServiceContainer


The ConfigurationDesignHost is created when the Enterprise Library Configuration Tool starts, and it acts as the hub for design-time configuration-related objects and services. As previously mentioned, this class is a container for configuration nodes and design-time services.

As configuration nodes are added to an application's configuration, the ConfigurationDesignHost object creates an object of type ConfigurationNodeSite for the nodes. At this point, the component is known to be sited and is fully functional. Since the ConfigurationNodeSite object implements the ISite interface, it lets the configuration node access the services hosted by the ConfigurationDesignHost object.

Table 2.3 lists the services initialized by the ConfigurationDesignHost object when it is created.

Table 2.3. Services Initialized and Added by the ConfigurationDesignHost

Service

Description

NodeNameCreationService

Generates a unique name for a node. All child nodes under a parent node must have a unique name. The Configuration Application Block uses this service to create a new name when a node is created with the same name as a sibling node.

UIHierarchyService

Provides a container and management services for objects that implement the IUIHierarchy interface. The command to create an application configuration node creates an IUIHierarchy object for the application and adds this hierarchy to the collection maintained by the UIHierarchyService class.

ConfigurationErrorService

Collects configuration and validation errors. The application block design managers use this service to report errors that occur when an application block configuration is opened or saved. The command to validate configuration nodes also uses this service to report validation errors.

NodeCreationService

Creates configuration nodes. It allows design managers to map runtime configuration data types to configuration node types. Configuration nodes also use this service to create child nodes based on runtime configuration object types.

XmlIncludeTypeService

Adds XmlIncludeTypes to the metaconfiguration data. It is typically used when providing extension points to existing applications.

LinkNodeService

Links one configuration node to another. A configuration node can have a property that specifies another configuration node as the value for that property. Configuration nodes use this service to create a link between the two nodes.

MenuContainerService

Adds menu items to a menu. Configuration nodes use this service to create menu items to be added to the context menu for that node.


Because a configuration node can access the container via the Site property that has been set for it, the node can perform actions requiring services by calling Site.GetService(Type). IServiceProvider.GetService(Type) allows dynamic retrieval of services from the container. Thus, new configuration nodes can be created and dynamically added to the ConfigurationDesignHost that can access and use the services provided by the Enterprise Library's Configuration design-time.

Configuration Hierarchies

Configuration hierarchies maintain a logical structure and grouping for configuration settings. Configuration nodes can have a parent node, child nodes, and sibling nodes. Every configuration hierarchy has a single root node.

Hierarchies must conform to the IUIHierarchy interface. The IUIHierarchy interface can prove useful because it has methods to search for nodes either by node type or by name. This becomes especially important when a configuration node needs to reference another configuration node in an application. For example, Figure 2.19 shows a DatabaseInstance node for the Data Access Application Block referencing a ConnectionString node and a DatabaseType node. The IUIHierarchy interface provides this configuration node with the capability to return a list of the types of these nodes (i.e., ConnectionString node and DatabaseType node) that have already been configured for the application.

Configuration Menu Items and Commands

Configuration menu items and commands provide the user interface for launching configuration-related actions at design time. For example, as depicted in Figure 2.23, a command on the Data Access Application Block ConnectionStrings configuration node lets users create new connection strings as child nodes.

Figure 2.23. Configuration Menu Items and Commands


Actions are exposed as configuration menu items. Configuration menu items are classes that derive from the ConfigurationMenuItem class. Common menu items that exist for many configuration nodes are New, Rename, Remove, Validate, New Application, and Save Application. You can add custom menu items to a configuration node by overriding the OnAddMenuItems method.

A configuration node command determines the action performed when a user selects a menu item. The Enterprise Library Configuration design-time follows the command design pattern[1] in its implementation for commands. The Configuration Application Block includes an abstract ConfigurationNodeCommand base class from which all concrete Command classes must derive. The base class defines an Execute method that gets called when the command is executed. However, this method passes control to a derived class' implementation of the virtual ExecuteCore method.

[1] Design Patterns: Elements of Reusable Object-Oriented Software, by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. Addison-Wesley, 1995.

For example, the AddChildNodeCommand command adds a configuration node as a child of the currently selected configuration node. The logic for the actions that take place when this command is executed resides in the AddChildNodeCommand's ExecuteCore method. You can add new commands to the design-time experience by deriving a new class from the ConfigurationNodeCommand class and implementing the ExecuteCore method. Figure 2.24 shows a small sampling of the concrete commands that exist as part of the Configuration Application Block's design-time features.

Figure 2.24. ConfigurationNodeCommand Hierarchy


The ConfigurationDesignManager Class

The ConfigurationDesignManager provides the connection point between the Enterprise Library Configuration Tool and an application block's design-time support. The ConfigurationDesignManager creates menu items and commands that are invoked as a user interacts with the Enterprise Library Configuration Tool to configure an application block, and it is responsible for loading and saving configuration data.

The ConfigurationDesignManager is also the class that provides the capability for new application blocks to be "snapped into" the Enterprise Library Configuration Tool. The Configuration Tool discovers classes that implement the IConfigurationDesignManager interface by examining the assembly attributes for assemblies that it knows about, instantiating the type defined in the ConfigurationDesignManagerAttribute, and validating the type as an implementation of IConfigurationDesignManager. The IConfigurationDesignManager interface defines four methods: Register, Open, Save, and BuildContext. Table 2.4 details the significance of each of these methods.

Table 2.4. IConfigurationDesignManager Interface Methods

Method

Description

Register

Called when an application configuration node is selected. This method allows an application block to register a new menu item. This menu item contains the command to add the application block configuration to the current application and relates the menu item to its corresponding configuration node.

Open

Called when an application's configuration file is opened. This method loads the configuration data for all application blocks by calling each configured StorageProvider's Read method.

Save

Called when an application's configuration information is saved. This method saves all of an application block's configuration information to storage by calling each configured StorageProvider's Write method.

BuildContext

Creates an in-memory representation of the application block's configuration settings. This method does not require that these settings exist in configuration storage. The BuildContext method can construct configuration settings based on the state of the configuration settings of other application blocks. This allows an application block to be configured dynamically. (To see an example of using the ConfigurationContext to dynamically access the configuration settings for an application block, refer to the description of the DatabaseStorageProvider in Chapter 1.) The ConfigurationDesignManager determines the actions that occur when the Enterprise Library Configuration Tool is used to open or save an application's configuration information. For example, when an application that is configured to use the Data Access Application Block is opened with the Enterprise Library Configuration Tool, the following actions take place.


  1. The ConfigurationDesignManager's Open method is called for both the Configuration Application Block and the Data Access Application Block.

  2. The Configuration Application Block reads the configuration metadata about all configuration sections from the application domain configuration file (i.e., app.config or web.config).

  3. The configuration information for the Data Access Application Block is read from the configured StorageProviders and the BuildContext method is used to maintain it in the Configuration Application Block's current ConfigurationContext object.

  4. The Data Access Application Block's runtime components are instantiated with the information contained in the current ConfigurationContext.

  5. The ConfigurationDesignManager's Register method is called for each application block. This allows the Enterprise Library Configuration Tool to populate the configuration nodes, menus items, and commands. The settings that are displayed for each configuration node are obtained from the node's corresponding runtime object. For example, the DatabaseTypeNode configuration node encapsulates the Data Access Application Block's DatabaseTypeData object.

  6. Users can add, delete, or modify the configuration settings.

  7. As information is modified for the properties of a configuration node, the application block design-time objects update their runtime objects to reflect the changes.

  8. When the configuration information is saved in the Enterprise Library Configuration Tool, each ConfigurationDesignManager's Save method is called. This lets each design-time object perform validation on the data that exists in the runtime objects and report any failures through the tool.

  9. After validation succeeds, each application block writes the new configuration data to its respective data stores: the Configuration Application Block writes the settings to the application domain configuration file, and the Data Access Application Block uses its configured StorageProvider and Transformer to save its new configuration settings to the appropriate data store.




Fenster Effective Use of Microsoft Enterprise Library(c) Building Blocks for Creating Enterprise Applications and Services 2006
Effective Use of Microsoft Enterprise Library: Building Blocks for Creating Enterprise Applications and Services
ISBN: 0321334213
EAN: 2147483647
Year: 2004
Pages: 103
Authors: Len Fenster

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net