1 //------------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------------------------
4 
5 namespace System.ServiceModel.Configuration
6 {
7     using System;
8     using System.Configuration;
9 
10     [ConfigurationCollection(typeof(ExtensionElement), CollectionType = ConfigurationElementCollectionType.BasicMap)]
11     public class ExtensionElementCollection : ServiceModelConfigurationElementCollection<ExtensionElement>
12     {
ExtensionElementCollection()13         public ExtensionElementCollection()
14             : base(ConfigurationElementCollectionType.BasicMap, ConfigurationStrings.Add)
15         {
16         }
17 
BaseAdd(ConfigurationElement element)18         protected override void BaseAdd(ConfigurationElement element)
19         {
20             if (!this.InheritedElementExists((ExtensionElement)element))
21             {
22                 this.EnforceUniqueElement((ExtensionElement)element);
23                 base.BaseAdd(element);
24             }
25         }
26 
BaseAdd(int index, ConfigurationElement element)27         protected override void BaseAdd(int index, ConfigurationElement element)
28         {
29             if (!this.InheritedElementExists((ExtensionElement)element))
30             {
31                 this.EnforceUniqueElement((ExtensionElement)element);
32                 base.BaseAdd(index, element);
33             }
34         }
35 
GetElementKey(ConfigurationElement element)36         protected override object GetElementKey(ConfigurationElement element)
37         {
38             if (null == element)
39             {
40                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("element");
41             }
42 
43             ExtensionElement configElementKey = (ExtensionElement)element;
44             return configElementKey.Name;
45         }
46 
InheritedElementExists(ExtensionElement element)47         bool InheritedElementExists(ExtensionElement element)
48         {
49             // This is logic from ServiceModelEnhancedConfigurationElementCollection
50             // The idea is to allow duplicate identitcal extension definition in different level (i.e. app level and machine level)
51             // We however do not allow them on the same level.
52             // Identical extension is defined by same name and type.
53             object newElementKey = this.GetElementKey(element);
54             if (this.ContainsKey(newElementKey))
55             {
56                 ExtensionElement oldElement = (ExtensionElement)this.BaseGet(newElementKey);
57                 if (null != oldElement)
58                 {
59                     // Is oldElement present in the different level of original config
60                     // and name/type matching
61                     if (!oldElement.ElementInformation.IsPresent &&
62                         element.Type.Equals(oldElement.Type, StringComparison.Ordinal))
63                     {
64                         return true;
65                     }
66                 }
67             }
68 
69             return false;
70         }
71 
EnforceUniqueElement(ExtensionElement element)72         void EnforceUniqueElement(ExtensionElement element)
73         {
74             foreach (ExtensionElement extension in this)
75             {
76                 if (element.Name.Equals(extension.Name, StringComparison.Ordinal))
77                 {
78                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ConfigurationErrorsException(
79                         SR.GetString(SR.ConfigDuplicateExtensionName, element.Name)));
80                 }
81 
82                 bool foundDuplicateType = false;
83                 if (element.Type.Equals(extension.Type, StringComparison.OrdinalIgnoreCase))
84                 {
85                     foundDuplicateType = true;
86                 }
87                 else if (element.TypeName.Equals(extension.TypeName, StringComparison.Ordinal))
88                 {
89                     // In order to avoid extra assemblies being loaded, we perform type comparison only if the type names
90                     // are the same. See bug CSDMain 222573.
91                     Type elementType = Type.GetType(element.Type, false);
92                     if (null != elementType && elementType.Equals(Type.GetType(extension.Type, false)))
93                     {
94                         foundDuplicateType = true;
95                     }
96                 }
97 
98                 if (foundDuplicateType)
99                 {
100                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ConfigurationErrorsException(
101                         SR.GetString(SR.ConfigDuplicateExtensionType, element.Type)));
102                 }
103             }
104         }
105 
106         protected override bool ThrowOnDuplicate
107         {
108             get
109             {
110                 return true;
111             }
112         }
113     }
114 }
115