Design-Time Configuration


My goal is to make the process for creating, modifying, and validating the configuration settings for the Data Mapping Application Block very familiar to you if you have configured any of the application blocks that ship with Enterprise Library. This can be accomplished by adding design-time capabilities to the Data Mapping Application Block. Chapter 2 covered the Configuration Application Block's design-time capabilities in great depth, and you have seen how to provide design-time capabilities for custom providers in the previous chapters.

The process for adding design-time capabilities to an application block is not terribly different than it is for adding design-time capabilities for a custom provider to an existing application block. The primary difference is that you may need to create more configuration nodes to represent the runtime configuration classes for the application block and you may need to write additional code to consider the relationships between these classes. Thus, creating the design-time components for an application block can be broken down into three high-level steps.

1.

Create configuration nodes that map to runtime configuration classes and consider the relationships between other configuration nodes.

2.

Implement the IConfigurationDesignManager interface for the application block.

3.

Add a ConfigurationDesignManager attribute to the AssemblyInfo file for the assembly that contains the design-time classes.

Creating the Configuration Nodes

The first step in adding design-time behavior to an application block is to develop the configuration nodes that represent the information contained in the runtime configuration classes. The runtime classes should be designed so that they are optimized for containing the configuration information; the design-time classes should be designed so that they make adding and modifying configuration data easy and natural for an end user. While there is no rule that mandates a one-to-one relationship must exist between a configuration node and a runtime object, it is very common for configuration nodes to be designed this way.

The ability to add and modify configuration information for the Data Mapping Application Block must exist for each of the runtime configuration classes outlined in the previous section. Figure 9.5 depicts the configuration nodes that I have created for the Data Mapping Application Block: DataMappingSettingsNode, DataSetMappingProviderNode, DataSet-MappingNode, DataTableMappingNode, CommandMappingNode, SelectCommandMappingNode, CommandParameterMappingNode, and DataSet-CacheSettingsNode. Because most of these nodes simply wrap around the runtime classes that they represent, which is the same way that configuration nodes work for all the custom providers created so far in this book, I will not show the code for every design-time configuration class. There is, however, an exceptional difference in the way some of these classes needed to be written that wasn't covered in previous chapters.

Figure 9.5. Data Mapping Application Block's Design-Time Objects


The major difference with these configuration nodes that didn't need to be considered for any of the other extensions provided earlier in this book is how to represent the hierarchical relationship among the configuration nodes during the design-time experience. When a user creates a new DataSetMapping, I need to allow the user to create DataTableMappings and SelectCommandMappings as subnodes to the DataSetMappingNode. Likewise, I need to enable the user so that CommandMappings can be added underneath DataTableMappings, and CommandParameterMappings can be added underneath CommandMappings. I also need to ensure that this hierarchical representation can be saved and loaded properly in the Enterprise Library Configuration Tool.

The key to providing menu items and commands so that a child configuration node can be added to a parent configuration node lies in the OnAddMenuItems method. When every configuration node is added in the Enterprise Library Configuration Tool, its OnAddMenuItems method is called. It is the responsibility for every node in the configuration hierarchy to add menu items that will allow its child nodes to be added underneath it. To add a menu item, the base ConfigurationNode's AddMenuItem method can be called. Listing 9.6 shows how the DataSetMappingProviderNode calls the AddMenuItem method to add a menu item for adding a DataSetMappingNode as a child node in the hierarchy.

Listing 9.6. Adding Menu Items for the DataSetMappingProvider

[C#] protected override void OnAddMenuItems() {     base.OnAddMenuItems ();     AddMenuItem(new ConfigurationMenuItem(SR.DataMappingMenuText,               new AddChildNodeCommand(Site,               typeof(DataSetMappingNode)), this, Shortcut.None,               SR.DataMappingStatusText, InsertionPoint.New)); } [Visual Basic] Protected Overrides Sub OnAddMenuItems()     MyBase.OnAddMenuItems ()     AddMenuItem(New ConfigurationMenuItem(SR.DataMappingMenuText, New _               AddChildNodeCommand(Site, _               GetType(DataSetMappingNode)), Me, Shortcut.None, _               SR.DataMappingStatusText, InsertionPoint.New)) End Sub

Alternatively, rather than creating a new ConfigurationMenuItem and calling AddMenuItem, the base class' CreateDynamicMenuItems method can be used to dynamically create menu items for adding child nodes under a particular configuration node. For example, instead of creating a new ConfigurationMenuItem for a DataTableMappingNode and calling the AddMenuItem with it in the OnAddMenuItems for the DataSetMappingNode, CreateDynamicMenuItems can simply be called by passing in the DataTableMappingNode type. This will create the menu item for creating the DataTableMappingNode on behalf of the DataSetMappingNode as long as the child DataTableMappingNode nodes have been registered and configured properly. If they have not, then an exception will be thrown. This method determines valid child nodes that can be created by evaluating the XmlIncludeAttributes for the runtime configuration class that the configuration node wraps around.

For example, the runtime configuration class for the DataSetMappingNode is the DataSetMapping. The DataSetMapping class is attributed with an XmlIncludeAttribute with a value of DataTableMapping. For the purposes of creating dynamic menu items, this indicates that the DataTableMapping is a valid child of DataSetMapping. As long as the DataTableMappingNode is registered with the ConfigurationDesignManager as being linked to the DataTableMapping configuration class, then the Configuration Application Block will be able to create the menu items for creating the child nodes. Listing 9.7 shows how the CreateDynamicMenuItems method is used in the OnAddMenuItems method for the DataSetMappingNode.

Listing 9.7. Dynamically Adding Menu Items

[C#] protected override void OnAddMenuItems() {     base.OnAddMenuItems ();     base.CreateDynamicMenuItems(typeof(DataTableMappingNode));     base.CreateDynamicMenuItems(typeof(SelectCommandMappingNode));     //Use AddNodeMenu (which checks DoesChildNodeExist) so that     //we can only create one DataMappingProvider.     AddNodeMenu(typeof(DataSetCacheSettingsNode),          SR.DefaultDataSetCacheNodeName,SR.DataSetCacheStatusText); } [Visual Basic] Protected Overrides Sub OnAddMenuItems()     MyBase.OnAddMenuItems ()     MyBase.CreateDynamicMenuItems(GetType(DataTableMappingNode))     MyBase.CreateDynamicMenuItems(GetType(SelectCommandMappingNode))     'Use AddNodeMenu (which checks DoesChildNodeExist) so that     'we can only create one DataMappingProvider.     AddNodeMenu(GetType(DataSetCacheSettingsNode), _          SR.DefaultDataSetCacheNodeName,SR.DataSetCacheStatusText) End Sub

Configuration nodes often contain nonbrowsable properties that return the runtime configuration class around which they wrap. For example, the DatabaseStorageProviderNode contains a property that returns the DatabaseStorageProviderData class. Similarly, the DataSetMappingProviderNode contains a property that returns a DataSetMappingProviderData class. These properties are used by the ConfigurationDesignManager when saving the configuration information for an application block or provider.

The ConfigurationDesignManager does not iterate down the configuration hierarchy for every node that exists when it is saving the configuration data for those nodes. Instead, it uses this property for every provider that has been registered with it. If the provider has a deep hierarchy of configuration nodes, then it is the provider's responsibility to iterate through the list of nodes to set the configuration data contained in them. Because the configuration hierarchy underneath the DataSetMappingProviderNode is very deep, the code in its DataSetMappingProviderData property is pretty large and contains many loops in loops. Listing 9.8 shows the first few loops.

Listing 9.8. DataSetMappingProvider's DataMappingProviderData Property

[C#] public override DataMappingProviderData DataMappingProviderData {     get     {          DataSetMappingDataCollection mappings =               this.dataSetMappingProviderData.DataSetMappings;          // Empty the collection of runtime configuration data for          // datamappings and reconstruct it from the current          // configuration data represented by the nodes.          mappings.Clear();          // Loop through all the DataMappingNodes and          // add their configuration data to the collection.          foreach (ConfigurationNode node in Nodes)          {               DataSetMappingNode dataSetMappingNode =                    node as DataSetMappingNode;          if (dataSetMappingNode != null)          {               DataSetMapping mapping =                    dataSetMappingNode.DataSetMapping;               if (mapping.DataTableMappings != null)                    mapping.DataTableMappings.Clear();               if (mapping.SelectCommands != null)                    mapping.SelectCommands.Clear();               foreach (ConfigurationNode childNode in                    dataSetMappingNode.Nodes)               {                    if (childNode != null)                    {                         if (childNode is SelectCommandMappingNode)                         {                              SelectCommandMappingNode                              selectCommandNode = childNode as                                   SelectCommandMappingNode;                              mapping.SelectCommands.Add                                   (selectCommandNode.CommandMapping);                    }                    else if (childNode is                                   DataSetCacheSettingsNode)                    {                         DataSetCacheSettingsNode cacheNode =                              childNode as                              DataSetCacheSettingsNode; ...                    }                    else                    {                         DataTableMappingNode tableNode =                              childNode as DataTableMappingNode;                         DataTableMapping dtMapping =                              tableNode.DataTableMapping;                         dtMapping.CommandMappings.Clear();                         foreach (ConfigurationNode dtChildNode in                              tableNode.Nodes)                         {                              ...                         }                         mapping.Add(dtMapping);                    } //end else                 } //end if            }            mappings.Add(mapping);            }          }     return this.dataSetMappingProviderData;     } } [Visual Basic] Public Overrides ReadOnly Property DataMappingProviderData() _               As DataMappingProviderData Get     Dim mappings As DataSetMappingDataCollection = _          Me.dataSetMappingProviderData.DataSetMappings     ' Empty the collection of runtime configuration data for     ' datamappings and reconstruct it from the current     ' configuration data represented by the nodes.     mappings.Clear()     ' Loop through all the DataMappingNodes and     ' add their configuration data to the collection.     For Each node As ConfigurationNode In Nodes          Dim dataSetMappingNode As DataSetMappingNode = _               IIf(TypeOf node Is DataSetMappingNode, _                    CType(node, DataSetMappingNode), _                    CType(Nothing, DataSetMappingNode))          If Not dataSetMappingNode Is Nothing Then            Dim mapping As DataSetMapping = _               dataSetMappingNode.DataSetMapping               If Not mapping.DataTableMappings Is Nothing Then                    mapping.DataTableMappings.Clear()               End If               If Not mapping.SelectCommands Is Nothing Then                    mapping.SelectCommands.Clear()               End If               For Each childNode As ConfigurationNode In _                    dataSetMappingNode.Nodes                    If Not childNode Is Nothing Then                         If TypeOf childNode Is _                              SelectCommandMappingNode Then                         Dim selectCommandNode As _                              SelectCommandMappingNode = _                              IIf(TypeOf childNode Is _                              SelectCommandMappingNode, _                              CType(childNode, _                              SelectCommandMappingNode), _                              CType(Nothing, _                              SelectCommandMappingNode))                         mapping.SelectCommands.Add _                              (selectCommandNode.CommandMapping)                    Else If TypeOf childNode Is _                         DataSetCacheSettingsNode Then                         Dim cacheNode As DataSetCacheSettingsNode _                              = IIf(TypeOf childNode Is _                                   DataSetCacheSettingsNode, _                                   CType(childNode, _                                   DataSetCacheSettingsNode), _                                   CType(Nothing, _                                   DataSetCacheSettingsNode))                                   ...                      Else                          Dim tableNode As DataTableMappingNode = _                                   IIf(TypeOf childNode Is _                                   DataTableMappingNode, _                                   CType(childNode, _                                   DataTableMappingNode), _                                   CType(Nothing, _                                   DataTableMappingNode))                         Dim dtMapping As DataTableMapping = _                              tableNode.DataTableMapping                         dtMapping.CommandMappings.Clear()                        For Each dtChildNode As ConfigurationNode _                              In tableNode.Nodes                              ...                        Next dtChildNode                        mapping.Add(dtMapping)                      End If 'end else                 End If 'end if            Next childNode            mappings.Add(mapping)          End If       Next node       Return Me.dataSetMappingProviderData End Get End Property

On the reverse side, the configuration nodes for an application block or provider will get loaded starting from the root of the configuration data's hierarchy. To accomplish this, each node in the hierarchy is responsible for creating its child nodes. At startup, the Enterprise Library Configuration Tool creates a container, ConfigurationDesignHost, to host all configuration nodes. When a node is added to the configuration hierarchy, the Configuration Application Block adds the node to the ConfigurationDesignHost container and calls the node's OnSited method. This is the name of the node's Site property, which also appears as the name of the node in the configuration tree. Since the OnSited method always gets called when a node is added to the configuration hierarchy, it makes sense that this method should also be responsible for notifying the Configuration Application Block about its child nodes that also need to be added to the configuration hierarchy.

For example, when the OnSited method gets called in the DataSetMappingProvider, it creates a child DataSetMappingNode for every Data-SetMapping that is contained in the configuration data. When each Data-SetMappingNode's OnSited method is called, it tells the Configuration Application Block to add SelectCommandMappingNodes and DataTable-MappingNodes for every SelectCommandMapping and DataTableMapping that is configured for that DataSetMapping. This process continues down the configuration hierarchy until all of the ConfigurationParameterMappingNodes are created and the nodes for all the configuration data in the hierarchy have been created. Listing 9.9 shows the code for the DataSetMappingProviderNode's OnSited method.

Listing 9.9. DataSetMappingProvider's OnSited Method

[C#] protected override void OnSited() {      base.OnSited();      Site.Name = this.dataSetMappingProviderData.Name;      // If this node represents a provider whose configuration is      // being loaded from storage, then it may have existing data      // mappings. Loop through the configuration data and      // create child nodes for any existing data mappings.      foreach (DataSetMapping dataSetMapping in                  this.dataSetMappingProviderData.DataSetMappings)      {        Nodes.Add(new DataSetMappingNode(dataSetMapping));      } } [Visual Basic] Protected Overrides Sub OnSited()       MyBase.OnSited()       Site.Name = Me.dataSetMappingProviderData.Name       ' If this node represents a provider whose configuration is       ' being loaded from storage, then it may have existing data       ' mappings. Loop through the configuration data and       ' create child nodes for any existing data mappings.       For Each dataSetMapping As DataSetMapping In _               Me.dataSetMappingProviderData.DataSetMappings          Nodes.Add(New DataSetMappingNode(dataSetMapping))       Next dataSetMapping End Sub

Rather than explicitly looping through the configuration data that represents all the child elements for a node and calling Node.Add, the CreateDynamicNodes method can be used to dynamically create child nodes for a configuration node. This works similarly to the way CreateDynamicMenuItems works. As long as the child node is registered with the ConfigurationDesignManager, its parent node has been developed so that it signifies this child node to be valid, and the child node is linked properly to its runtime configuration object, the Configuration Application Block will be able to create the child nodes. Listing 9.10 shows how the CreateDynamicNodes method can be used to automatically create all child Data-TableMappingNodes and SelectCommandMappingNodes for the Data-SetMappingNode.

Listing 9.10. Dynamically Creating Child Nodes

[C#] protected override void OnSited() {     base.OnSited();     Site.Name = this.dataSetMapping.Name;     if (dataSetMapping.CacheSettings != null)          Nodes.Add(new DataSetCacheSettingsNode                (dataSetMapping.CacheSettings));     base.CreateDynamicNodes(this.dataSetMapping.DataTableMappings);     base.CreateDynamicNodes(this.dataSetMapping.SelectCommands); } [Visual Basic] Protected Overrides Sub OnSited()     MyBase.OnSited()     Site.Name = Me.dataSetMapping.Name     If Not dataSetMapping.CacheSettings Is Nothing Then          Nodes.Add(New DataSetCacheSettingsNode _                  (dataSetMapping.CacheSettings))     End If     MyBase.CreateDynamicNodes(Me.dataSetMapping.DataTableMappings)     MyBase.CreateDynamicNodes(Me.dataSetMapping.SelectCommands) End Sub

Implementing the ConfigurationDesignManager

Failure to register the runtime data types for configuration node types will cause an exception to be thrown on a call to CreateDynamicNodes or CreateDynamicMenuItems. Registration of these nodes occurs in the Register method for the specific ConfigurationDesignManager for an application block or provider. Every application block must contain a class that implements the IConfigurationDesignManager interface for the design-time classes to operate in the Enterprise Library Configuration Tool. This class provides the entry point to an application block's design-time configuration capabilities. The DataMappingConfigurationDesign is the implementation of this interface for the Data Mapping Application Block and is depicted in Figure 9.6.

Chapter 2 covered the IConfigurationManager interface and the base ConfigurationDesignManager class, so I won't repeat all the same information here. One of the things that makes the DataMappingConfigurationDesignManager a bit different from all the others created in the previous chapters is how the configuration nodes are registered such that the CreateDynamicNodes and CreateDynamicMenuItems methods can be used to create child nodes underneath another node in the configuration hierarchy. The code for this registration occurs in the private Register-NodeMaps method which is called from the public virtual Register method. Listing 9.11 shows this code.

Figure 9.6. The DataMappingConfigurationDesignManager Class


Listing 9.11. Registering Configuration Nodes in the ConfigurationDesignManager

[C#] private static void RegisterNodeMaps(IServiceProvider serviceProvider) {     // Retrieve the INodeCreationService, which associates node     // types with runtime configuration data types.     INodeCreationService nodeCreationService =          serviceProvider.GetService(typeof(INodeCreationService)) as          INodeCreationService;     // Associate the nodes for providers with their respective     // runtime configuration data types. Once associated, provider     // nodes can be created from their runtime configuration     // data types.     Type nodeType = typeof(DataSetMappingProviderNode);     NodeCreationEntry entry =          NodeCreationEntry.CreateNodeCreationEntryWithMultiples          (new AddChildNodeCommand(serviceProvider, nodeType),          nodeType, typeof(DataSetMappingProviderData),          SR.DefaultDataSetMappingProviderNodeName);     nodeCreationService.AddNodeCreationEntry(entry);     nodeType = typeof(DataTableMappingNode);     entry =          NodeCreationEntry.CreateNodeCreationEntryWithMultiples          (new AddChildNodeCommand(serviceProvider, nodeType),          nodeType, typeof(DataTableMapping),          SR.DefaultDataTableMappingProviderNodeName);     nodeCreationService.AddNodeCreationEntry(entry);     nodeType = typeof(CommandMappingNode);     entry =          NodeCreationEntry.CreateNodeCreationEntryWithMultiples          (new AddChildNodeCommand(serviceProvider, nodeType),          nodeType, typeof(CommandMapping),          SR.DefaultCommandMappingProviderNodeName);     nodeCreationService.AddNodeCreationEntry(entry);     nodeType = typeof(SelectCommandMappingNode);     entry =          NodeCreationEntry.CreateNodeCreationEntryWithMultiples          (new AddChildNodeCommand(serviceProvider, nodeType),          nodeType, typeof(SelectCommandMapping),          SR.DefaultSelectCommandMappingProviderNodeName);     nodeCreationService.AddNodeCreationEntry(entry);     nodeType = typeof(CommandParameterMappingNode);     entry =          NodeCreationEntry.CreateNodeCreationEntryWithMultiples          (new AddChildNodeCommand(serviceProvider, nodeType),          nodeType, typeof(CommandParameterMapping),     SR.DefaultCommandParameterMappingProviderNodeName);     nodeCreationService.AddNodeCreationEntry(entry); } [Visual Basic] Private Shared Sub RegisterNodeMaps _           (ByVal serviceProvider As IServiceProvider)     ' Retrieve the INodeCreationService, which associates node     ' types with runtime configuration data types.     Dim nodeCreationService As INodeCreationService = _          IIf(TypeOf serviceProvider.GetService _          (GetType(INodeCreationService)) Is INodeCreationService, _          CType(serviceProvider.GetService _          (GetType(INodeCreationService)), INodeCreationService), _          CType(Nothing, INodeCreationService))     ' Associate the nodes for providers with their respective     ' runtime configuration data types. Once associated, provider     ' nodes can be created from their runtime configuration     ' data types.     Dim nodeType As Type = GetType(DataSetMappingProviderNode)     Dim entry As NodeCreationEntry = _          NodeCreationEntry.CreateNodeCreationEntryWithMultiples _          (New AddChildNodeCommand(serviceProvider, nodeType), _          nodeType, GetType(DataSetMappingProviderData), _          SR.DefaultDataSetMappingProviderNodeName)     nodeCreationService.AddNodeCreationEntry(entry)     nodeType = GetType(DataTableMappingNode)     entry = NodeCreationEntry.CreateNodeCreationEntryWithMultiples _          (New AddChildNodeCommand(serviceProvider, nodeType), _          nodeType, GetType(DataTableMapping), _          SR.DefaultDataTableMappingProviderNodeName)     nodeCreationService.AddNodeCreationEntry(entry)     nodeType = GetType(CommandMappingNode)     entry = NodeCreationEntry.CreateNodeCreationEntryWithMultiples _          (New AddChildNodeCommand(serviceProvider, nodeType), _          nodeType, GetType(CommandMapping), _          SR.DefaultCommandMappingProviderNodeName)     nodeCreationService.AddNodeCreationEntry(entry)     nodeType = GetType(SelectCommandMappingNode)     entry = NodeCreationEntry.CreateNodeCreationEntryWithMultiples _          (New AddChildNodeCommand(serviceProvider, nodeType), _          nodeType, GetType(CommandMapping), _          SR.DefaultSelectCommandMappingProviderNodeName)     nodeCreationService.AddNodeCreationEntry(entry)     nodeType = GetType(CommandParameterMappingNode)     entry = NodeCreationEntry.CreateNodeCreationEntryWithMultiples _          (New AddChildNodeCommand(serviceProvider, nodeType), _          nodeType, GetType(CommandMapping), _          SR.DefaultCommandParameterMappingProviderNodeName)     nodeCreationService.AddNodeCreationEntry(entry) End Sub

Another important point to understand that wasn't obvious from the ConfigurationDesignManager's that were created in the previous chapters is what occurs when an application's configuration is saved. When an application's configuration is saved, the Configuration Application Block saves the metaconfiguration data about the application block's configuration sections to the application's domain configuration file. It then calls the Save method for every application block that the tool knows about, regardless of whether or not the application has been configured to use that application block.

In a similar way, it calls the Open method for every application block that the tool knows about when loading the configuration data for an application. Therefore, it is important to determine whether the configuration settings actually need to be loaded or saved to prevent unnecessary reads and writes from and to the configured StorageProvider. The check and subsequent save to storage occurs in the DataMappingConfigurationDesignManager's Save method, which is shown in Listing 9.12. Similar checks exist for the Open method.

Listing 9.12. DataMappingConfigurationDesignManager's Save Method

[C#] public void Save(IServiceProvider serviceProvider) {     ConfigurationContext builder =          ServiceHelper.GetCurrentConfigurationContext          (serviceProvider);     // Verify that the application has been configured to use     // the Data Mapping Application Block.     if (builder.IsValidSection(DataMappingSettings.SectionName))     {          DataMappingsSettingsNode dataMappingsSettingsNode = null;          try          {               // Attempt to retrieve the node that has the               // DataMappingSettings.               IUIHierarchy hierarchy =                    ServiceHelper.GetCurrentHierarchy                     (serviceProvider);               dataMappingsSettingsNode =                    hierarchy.FindNodeByType(typeof                    (DataMappingsSettingsNode)) as                    DataMappingsSettingsNode;               // If application isn't configured to use the block               // the node won't be found.               if (dataMappingsSettingsNode == null)               {                    return;               }               // Save the settings to storage.               DataMappingSettings dataMappingSettings =               dataMappingsSettingsNode.DataMappingsSettings;               builder.WriteConfiguration               (DataMappingSettings.SectionName, dataMappingSettings);          }          catch (ConfigurationException e)          {               ServiceHelper.LogError               (serviceProvider, dataMappingsSettingsNode, e);          }          catch (InvalidOperationException e)          {               ServiceHelper.LogError               (serviceProvider, dataMappingsSettingsNode, e);          }     } } [Visual Basic] Public Sub Save(ByVal serviceProvider As IServiceProvider)     Dim builder As ConfigurationContext = _          ServiceHelper.GetCurrentConfigurationContext _          (serviceProvider)     ' Verify that the application has been configured to use     ' the Data Mapping Application Block.     If builder.IsValidSection(DataMappingSettings.SectionName) Then          Dim dataMappingsSettingsNode As DataMappingsSettingsNode = _               Nothing          Try               ' Attempt to retrieve the node that has the               ' DataMappingSettings.               Dim hierarchy As IUIHierarchy = _                    ServiceHelper.GetCurrentHierarchy _                    (serviceProvider)               dataMappingsSettingsNode = IIf(TypeOf _                    hierarchy.FindNodeByType _                    (GetType(DataMappingsSettingsNode)) Is _                    DataMappingsSettingsNode, _                    CType(hierarchy.FindNodeByType _                    (GetType(DataMappingsSettingsNode)), _                    DataMappingsSettingsNode), _                    CType(Nothing, DataMappingsSettingsNode))               ' If application isn't configured to use the block               ' the node won't be found.               If dataMappingsSettingsNode Is Nothing Then                    Return               End If               ' Save the settings to storage.               Dim dataMappingSettings As DataMappingSettings = _                    dataMappingsSettingsNode.DataMappingsSettings               builder.WriteConfiguration _               (DataMappingSettings.SectionName, _                    dataMappingSettings)          Catch e As ConfigurationException               ServiceHelper.LogError _                     (serviceProvider, dataMappingsSettingsNode, e)          Catch e As InvalidOperationException               ServiceHelper.LogError _                    (serviceProvider, dataMappingsSettingsNode, e)          End Try     End If End Sub

Adding the ConfigurationDesignManager Attribute

After the configuration nodes and ConfigurationDesignManager have been developed, the coding for the application block is complete. However, one more task still needs to be completed. If the assemblies that contain the runtime and design-time classes for the application block are placed in the same directory as the Enterprise Library Configuration Tool, there still won't be a way to create the application block. This is because the tool does not recognize the assembly unless an assembly attribute with the type of the ConfigurationDesignManager that provides the entry point for this application block has been added to the assembly's AssemblyInfo file.

Listing 9.13 shows how to add this attribute to the AssemblyInfo file for the Data Mapping Application Block. Once this attribute has been added and the assemblies have been compiled and deployed to the same directory as the Enterprise Library Configuration Tool, a menu item will appear in the tool for adding the Data Mapping Application Block.

Listing 9.13. Adding the ConfigurationDesignManager Attribute to the AssemblyInfo File

[C#] [assembly: ConfigurationDesignManager(     typeof(DataMappingConfigurationDesignManager))] [Visual Basic] <Assembly: ConfigurationDesignManager(     GetType(DataMappingConfigurationDesignManager))>

Figure 9.7 illustrates what the configuration hierarchy might look like in the Enterprise Library Configuration Tool for an application that has been configured to use the Data Mapping Application Block.

Figure 9.7. Configuration Hierarchy for the Data Mapping Application Block





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