//------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ namespace System.ServiceModel.Configuration { using System.Collections.Generic; using System.Configuration; using System.Reflection; using System.Runtime; using System.Security; using System.ServiceModel; using System.ServiceModel.Description; using System.Xml; using System.Runtime.Diagnostics; public sealed partial class StandardEndpointsSection : ConfigurationSection, IConfigurationContextProviderInternal { static Configuration configuration; ConfigurationPropertyCollection properties; public StandardEndpointsSection() { } Dictionary EndpointCollectionElements { get { Dictionary endpointCollectionElements = new Dictionary(); foreach (ConfigurationProperty property in this.Properties) { endpointCollectionElements.Add(property.Name, this[property.Name]); } return endpointCollectionElements; } } new public EndpointCollectionElement this[string endpoint] { get { return (EndpointCollectionElement)base[endpoint]; } } protected override ConfigurationPropertyCollection Properties { get { if (this.properties == null) { this.properties = new ConfigurationPropertyCollection(); } this.UpdateEndpointSections(); return this.properties; } } [ConfigurationProperty(ConfigurationStrings.MexStandardEndpointCollectionElementName, Options = ConfigurationPropertyOptions.None)] public ServiceMetadataEndpointCollectionElement MexEndpoint { get { return (ServiceMetadataEndpointCollectionElement)base[ConfigurationStrings.MexStandardEndpointCollectionElementName]; } } // This property should only be called/set from EndpointsSectionGroup TryAdd static Configuration Configuration { get { return StandardEndpointsSection.configuration; } set { StandardEndpointsSection.configuration = value; } } public static StandardEndpointsSection GetSection(Configuration config) { if (config == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("config"); } return (StandardEndpointsSection)config.GetSection(ConfigurationStrings.StandardEndpointsSectionPath); } public List EndpointCollections { get { List endpointCollections = new List(); foreach (ConfigurationProperty property in this.Properties) { endpointCollections.Add(this[property.Name]); } return endpointCollections; } } internal static bool TryAdd(string name, ServiceEndpoint endpoint, Configuration config, out string endpointSectionName) { bool retval = false; StandardEndpointsSection.Configuration = config; try { retval = StandardEndpointsSection.TryAdd(name, endpoint, out endpointSectionName); } finally { StandardEndpointsSection.Configuration = null; } return retval; } protected override bool OnDeserializeUnrecognizedElement(string elementName, XmlReader reader) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new ConfigurationErrorsException(SR.GetString(SR.ConfigEndpointExtensionNotFound, ConfigurationHelpers.GetEndpointsSectionPath(elementName)))); } internal static bool TryAdd(string name, ServiceEndpoint endpoint, out string endpointSectionName) { // TryAdd built on assumption that StandardEndpointsSectionGroup.Configuration is valid. // This should be protected at the callers site. If assumption is invalid, then // configuration system is in an indeterminate state. Need to stop in a manner that // user code can not capture. if (null == StandardEndpointsSection.Configuration) { Fx.Assert("The TryAdd(string name, ServiceEndpoint endpoint, Configuration config, out string endpointSectionName) variant of this function should always be called first. The Configuration object is not set."); DiagnosticUtility.FailFast("The TryAdd(string name, ServiceEndpoint endpoint, Configuration config, out string endpointSectionName) variant of this function should always be called first. The Configuration object is not set."); } bool retval = false; string outEndpointSectionName = null; StandardEndpointsSection sectionGroup = StandardEndpointsSection.GetSection(StandardEndpointsSection.Configuration); sectionGroup.UpdateEndpointSections(); foreach (string sectionName in sectionGroup.EndpointCollectionElements.Keys) { EndpointCollectionElement endpointCollectionElement = sectionGroup.EndpointCollectionElements[sectionName]; MethodInfo tryAddMethod = endpointCollectionElement.GetType().GetMethod("TryAdd", BindingFlags.Instance | BindingFlags.NonPublic); if (tryAddMethod != null) { retval = (bool)tryAddMethod.Invoke(endpointCollectionElement, new object[] { name, endpoint, StandardEndpointsSection.Configuration }); if (retval) { outEndpointSectionName = sectionName; break; } } } // This little oddity exists to make sure that the out param is assigned to before the method // exits. endpointSectionName = outEndpointSectionName; return retval; } void UpdateEndpointSections() { UpdateEndpointSections(ConfigurationHelpers.GetEvaluationContext(this)); } [Fx.Tag.SecurityNote(Critical = "Calls SecurityCritical methods UnsafeLookupCollection which elevates in order to load config.", Safe = "Does not leak any config objects.")] [SecuritySafeCritical] internal void UpdateEndpointSections(ContextInformation evaluationContext) { ExtensionElementCollection endpointExtensions = ExtensionsSection.UnsafeLookupCollection(ConfigurationStrings.EndpointExtensions, evaluationContext); // Extension collections are additive only (BasicMap) and do not allow for // or tags, nor do they allow for overriding an entry. This allows us // to optimize this to only walk the binding extension collection if the counts // mismatch. if (endpointExtensions.Count != this.properties.Count) { foreach (ExtensionElement endpointExtension in endpointExtensions) { if (null != endpointExtension) { if (!this.properties.Contains(endpointExtension.Name)) { Type extensionType = Type.GetType(endpointExtension.Type, false); if (extensionType == null) { ConfigurationHelpers.TraceExtensionTypeNotFound(endpointExtension); } else { ConfigurationProperty property = new ConfigurationProperty(endpointExtension.Name, extensionType, null, ConfigurationPropertyOptions.None); this.properties.Add(property); } } } } } } [Fx.Tag.SecurityNote(Critical = "Calls SecurityCritical methods UnsafeGetAssociatedBindingCollectionElement which elevates in order to load config.", Safe = "Does not leak any config objects.")] [SecuritySafeCritical] internal static void ValidateEndpointReference(string endpoint, string endpointConfiguration, ContextInformation evaluationContext, ConfigurationElement configurationElement) { // ValidateEndpointReference built on assumption that evaluationContext is valid. // This should be protected at the callers site. If assumption is invalid, then // configuration system is in an indeterminate state. Need to stop in a manner that // user code can not capture. if (null == evaluationContext) { Fx.Assert("ValidateEndpointReference() should only called with valid ContextInformation"); DiagnosticUtility.FailFast("ValidateEndpointReference() should only called with valid ContextInformation"); } if (!String.IsNullOrEmpty(endpoint)) { EndpointCollectionElement endpointCollectionElement = null; if (null != evaluationContext) { endpointCollectionElement = ConfigurationHelpers.UnsafeGetAssociatedEndpointCollectionElement(evaluationContext, endpoint); } else { endpointCollectionElement = ConfigurationHelpers.UnsafeGetEndpointCollectionElement(endpoint); } if (endpointCollectionElement == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ConfigurationErrorsException(SR.GetString(SR.ConfigInvalidSection, ConfigurationHelpers.GetEndpointsSectionPath(endpoint)), configurationElement.ElementInformation.Source, configurationElement.ElementInformation.LineNumber)); } if (!String.IsNullOrEmpty(endpointConfiguration)) { if (!endpointCollectionElement.ContainsKey(endpointConfiguration)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ConfigurationErrorsException(SR.GetString(SR.ConfigInvalidEndpointName, endpointConfiguration, ConfigurationHelpers.GetEndpointsSectionPath(endpoint), ConfigurationStrings.EndpointConfiguration), configurationElement.ElementInformation.Source, configurationElement.ElementInformation.LineNumber)); } } } } ContextInformation IConfigurationContextProviderInternal.GetEvaluationContext() { return this.EvaluationContext; } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview -- the return value will be used for a security decision -- see comment in interface definition.")] ContextInformation IConfigurationContextProviderInternal.GetOriginalEvaluationContext() { Fx.Assert("Not implemented: IConfigurationContextProviderInternal.GetOriginalEvaluationContext"); return null; } } }