//----------------------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- namespace System.ServiceModel.Description { using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Globalization; using System.Runtime; using System.Security; using System.ServiceModel; using System.ServiceModel.Channels; using System.Text; using System.Xml; using System.Xml.Schema; using ConfigNS = System.ServiceModel.Configuration; using WsdlConfigNS = System.Web.Services.Configuration; using WsdlNS = System.Web.Services.Description; public class WsdlImporter : MetadataImporter { readonly Dictionary importErrors = new Dictionary(); bool isFaulted = false; readonly Dictionary importedPortTypes = new Dictionary(); readonly Dictionary importedBindings = new Dictionary(); readonly Dictionary importedPorts = new Dictionary(); readonly KeyedByTypeCollection wsdlExtensions; readonly WsdlNS.ServiceDescriptionCollection wsdlDocuments = new WsdlNS.ServiceDescriptionCollection(); readonly XmlSchemaSet xmlSchemas = WsdlExporter.GetEmptySchemaSet(); readonly Dictionary policyDocuments = new Dictionary(); readonly Dictionary warnings = new Dictionary(); WsdlPolicyReader wsdlPolicyReader; bool beforeImportCalled = false; public WsdlImporter(MetadataSet metadata) : this(metadata, null, null, MetadataImporterQuotas.Defaults) { } public WsdlImporter(MetadataSet metadata, IEnumerable policyImportExtensions, IEnumerable wsdlImportExtensions) : this(metadata, policyImportExtensions, wsdlImportExtensions, MetadataImporterQuotas.Defaults) { } public WsdlImporter(MetadataSet metadata, IEnumerable policyImportExtensions, IEnumerable wsdlImportExtensions, MetadataImporterQuotas quotas) : base(policyImportExtensions, quotas) { // process wsdl extensions first for consistency with policy extensions (which are processed in base ctor) if (wsdlImportExtensions == null) { wsdlImportExtensions = LoadWsdlExtensionsFromConfig(); } this.wsdlExtensions = new KeyedByTypeCollection(wsdlImportExtensions); // then look at metadata if (metadata == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("metadata"); this.ProcessMetadataDocuments(metadata.MetadataSections); } public KeyedByTypeCollection WsdlImportExtensions { get { return this.wsdlExtensions; } } public WsdlNS.ServiceDescriptionCollection WsdlDocuments { get { return this.wsdlDocuments; } } public XmlSchemaSet XmlSchemas { get { return this.xmlSchemas; } } WsdlPolicyReader PolicyReader { get { if (this.wsdlPolicyReader == null) { this.wsdlPolicyReader = new WsdlPolicyReader(this); } return wsdlPolicyReader; } } //Consider this should be made public internal override XmlElement ResolvePolicyReference(string policyReference, XmlElement contextAssertion) { return this.PolicyReader.ResolvePolicyReference(policyReference, contextAssertion); } public override Collection ImportAllContracts() { if (this.isFaulted) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.WsdlImporterIsFaulted))); EnsureBeforeImportCalled(); Collection contracts = new Collection(); foreach (WsdlNS.ServiceDescription wsdl in this.wsdlDocuments) foreach (WsdlNS.PortType wsdlPortType in wsdl.PortTypes) { if (IsBlackListed(wsdlPortType)) continue; ContractDescription contract = ImportWsdlPortType(wsdlPortType, WsdlPortTypeImportOptions.ReuseExistingContracts, ErrorBehavior.DoNotThrowExceptions); if (contract != null) contracts.Add(contract); } return contracts; } public override ServiceEndpointCollection ImportAllEndpoints() { if (this.isFaulted) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.WsdlImporterIsFaulted))); EnsureBeforeImportCalled(); ServiceEndpointCollection endpoints = new ServiceEndpointCollection(); foreach (WsdlNS.Port wsdlPort in this.GetAllPorts()) { if (IsBlackListed(wsdlPort)) continue; ServiceEndpoint endpoint = ImportWsdlPort(wsdlPort, ErrorBehavior.DoNotThrowExceptions); if (endpoint != null) endpoints.Add(endpoint); } return endpoints; } public Collection ImportAllBindings() { if (this.isFaulted) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.WsdlImporterIsFaulted))); EnsureBeforeImportCalled(); Collection bindings = new Collection(); foreach (WsdlNS.Binding wsdlBinding in this.GetAllBindings()) { WsdlEndpointConversionContext importedBindingContext = null; if (IsBlackListed(wsdlBinding)) continue; importedBindingContext = ImportWsdlBinding(wsdlBinding, ErrorBehavior.DoNotThrowExceptions); if (importedBindingContext != null) bindings.Add(importedBindingContext.Endpoint.Binding); } return bindings; } // WSDL Specific methods public ContractDescription ImportContract(WsdlNS.PortType wsdlPortType) { if (this.isFaulted) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.WsdlImporterIsFaulted))); if (wsdlPortType == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("wsdlPortType"); return ImportWsdlPortType(wsdlPortType, WsdlPortTypeImportOptions.ReuseExistingContracts, ErrorBehavior.RethrowExceptions); } public Binding ImportBinding(WsdlNS.Binding wsdlBinding) { if (this.isFaulted) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.WsdlImporterIsFaulted))); if (wsdlBinding == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("wsdlBinding"); return ImportWsdlBinding(wsdlBinding, ErrorBehavior.RethrowExceptions).Endpoint.Binding; } public ServiceEndpoint ImportEndpoint(WsdlNS.Port wsdlPort) { if (this.isFaulted) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.WsdlImporterIsFaulted))); if (wsdlPort == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("wsdlPort"); return ImportWsdlPort(wsdlPort, ErrorBehavior.RethrowExceptions); } public ServiceEndpointCollection ImportEndpoints(WsdlNS.PortType wsdlPortType) { if (this.isFaulted) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.WsdlImporterIsFaulted))); if (wsdlPortType == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("wsdlPortType"); if (IsBlackListed(wsdlPortType)) throw CreateAlreadyFaultedException(wsdlPortType); else ImportWsdlPortType(wsdlPortType, WsdlPortTypeImportOptions.ReuseExistingContracts, ErrorBehavior.RethrowExceptions); ServiceEndpointCollection endpoints = new ServiceEndpointCollection(); foreach (WsdlNS.Binding wsdlBinding in FindBindingsForPortType(wsdlPortType)) if (!IsBlackListed(wsdlBinding)) foreach (ServiceEndpoint endpoint in ImportEndpoints(wsdlBinding)) endpoints.Add(endpoint); return endpoints; } internal ServiceEndpointCollection ImportEndpoints(ContractDescription contract) { if (this.isFaulted) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.WsdlImporterIsFaulted))); if (contract == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contract"); if (!this.KnownContracts.ContainsKey(WsdlExporter.WsdlNamingHelper.GetPortTypeQName(contract))) { Fx.Assert("WsdlImporter.ImportEndpoints(ContractDescription contract): !this.KnownContracts.ContainsKey(WsdlExporter.WsdlNamingHelper.GetPortTypeQName(contract))"); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.WsdlImporterContractMustBeInKnownContracts))); } EnsureBeforeImportCalled(); ServiceEndpointCollection endpoints = new ServiceEndpointCollection(); foreach (WsdlNS.Binding wsdlBinding in FindBindingsForContract(contract)) if (!IsBlackListed(wsdlBinding)) foreach (ServiceEndpoint endpoint in ImportEndpoints(wsdlBinding)) endpoints.Add(endpoint); return endpoints; } public ServiceEndpointCollection ImportEndpoints(WsdlNS.Binding wsdlBinding) { if (this.isFaulted) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.WsdlImporterIsFaulted))); if (wsdlBinding == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("wsdlBinding"); if (IsBlackListed(wsdlBinding)) throw CreateAlreadyFaultedException(wsdlBinding); else ImportWsdlBinding(wsdlBinding, ErrorBehavior.RethrowExceptions); ServiceEndpointCollection endpoints = new ServiceEndpointCollection(); foreach (WsdlNS.Port wsdlPort in FindPortsForBinding(wsdlBinding)) if (!IsBlackListed(wsdlPort)) { ServiceEndpoint endpoint = ImportWsdlPort(wsdlPort, ErrorBehavior.DoNotThrowExceptions); if (endpoint != null) endpoints.Add(endpoint); } return endpoints; } public ServiceEndpointCollection ImportEndpoints(WsdlNS.Service wsdlService) { if (this.isFaulted) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.WsdlImporterIsFaulted))); if (wsdlService == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("wsdlService"); EnsureBeforeImportCalled(); ServiceEndpointCollection endpoints = new ServiceEndpointCollection(); foreach (WsdlNS.Port wsdlPort in wsdlService.Ports) if (!IsBlackListed(wsdlPort)) { ServiceEndpoint endpoint = ImportWsdlPort(wsdlPort, ErrorBehavior.DoNotThrowExceptions); if (endpoint != null) endpoints.Add(endpoint); } return endpoints; } bool IsBlackListed(WsdlNS.NamedItem item) { return importErrors.ContainsKey(item); } ContractDescription ImportWsdlPortType(WsdlNS.PortType wsdlPortType, WsdlPortTypeImportOptions importOptions, ErrorBehavior errorBehavior) { if (IsBlackListed(wsdlPortType)) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateAlreadyFaultedException(wsdlPortType)); XmlQualifiedName wsdlPortTypeQName = new XmlQualifiedName(wsdlPortType.Name, wsdlPortType.ServiceDescription.TargetNamespace); ContractDescription contractDescription = null; if (importOptions == WsdlPortTypeImportOptions.IgnoreExistingContracts || !TryFindExistingContract(wsdlPortTypeQName, out contractDescription)) { EnsureBeforeImportCalled(); try { contractDescription = CreateContractDescription(wsdlPortType, wsdlPortTypeQName); WsdlContractConversionContext contractContext = new WsdlContractConversionContext(contractDescription, wsdlPortType); foreach (WsdlNS.Operation wsdlOperation in wsdlPortType.Operations) { OperationDescription operationDescription = CreateOperationDescription(wsdlPortType, wsdlOperation, contractDescription); contractContext.AddOperation(operationDescription, wsdlOperation); foreach (WsdlNS.OperationMessage wsdlOperationMessage in wsdlOperation.Messages) { MessageDescription messageDescription; if (TryCreateMessageDescription(wsdlOperationMessage, operationDescription, out messageDescription)) contractContext.AddMessage(messageDescription, wsdlOperationMessage); } foreach (WsdlNS.OperationFault wsdlOperationFault in wsdlOperation.Faults) { FaultDescription faultDescription; if (TryCreateFaultDescription(wsdlOperationFault, operationDescription, out faultDescription)) contractContext.AddFault(faultDescription, wsdlOperationFault); } } CallImportContract(contractContext); VerifyImportedWsdlPortType(wsdlPortType); importedPortTypes.Add(wsdlPortTypeQName, contractContext); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Fx.IsFatal(e)) throw; WsdlImportException wie = WsdlImportException.Create(wsdlPortType, e); LogImportError(wsdlPortType, wie); if (errorBehavior == ErrorBehavior.RethrowExceptions) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(wie); else return null; } } return contractDescription; } WsdlEndpointConversionContext ImportWsdlBinding(WsdlNS.Binding wsdlBinding, ErrorBehavior errorBehavior) { //Check for exisiting exception if (IsBlackListed(wsdlBinding)) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateAlreadyFaultedException(wsdlBinding)); XmlQualifiedName wsdlBindingQName = new XmlQualifiedName(wsdlBinding.Name, wsdlBinding.ServiceDescription.TargetNamespace); WsdlEndpointConversionContext bindingEndpointContext = null; if (!importedBindings.TryGetValue(wsdlBindingQName, out bindingEndpointContext)) { EnsureBeforeImportCalled(); try { bool wasExistingContract; ContractDescription contractDescription = GetOrImportContractDescription(wsdlBinding.Type, out wasExistingContract); WsdlContractConversionContext contractContext = null; importedPortTypes.TryGetValue(wsdlBinding.Type, out contractContext); ServiceEndpoint newWsdlBindingEndpoint = new ServiceEndpoint(contractDescription); bindingEndpointContext = new WsdlEndpointConversionContext(contractContext, newWsdlBindingEndpoint, wsdlBinding, null); foreach (WsdlNS.OperationBinding wsdlOperationBinding in wsdlBinding.Operations) try { OperationDescription operation = Binding2DescriptionHelper.FindOperationDescription(wsdlOperationBinding, wsdlDocuments, bindingEndpointContext); bindingEndpointContext.AddOperationBinding(operation, wsdlOperationBinding); for (int i = 0; i < operation.Messages.Count; i++) { MessageDescription message = operation.Messages[i]; WsdlNS.MessageBinding wsdlMessageBinding = Binding2DescriptionHelper.FindMessageBinding(wsdlOperationBinding, message); bindingEndpointContext.AddMessageBinding(message, wsdlMessageBinding); } foreach (FaultDescription fault in operation.Faults) { WsdlNS.FaultBinding wsdlFaultBinding = Binding2DescriptionHelper.FindFaultBinding(wsdlOperationBinding, fault); if (wsdlFaultBinding != null) { bindingEndpointContext.AddFaultBinding(fault, wsdlFaultBinding); } } } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Fx.IsFatal(e)) throw; throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(WsdlImportException.Create(wsdlOperationBinding, e)); } XmlQualifiedName bindingQName = WsdlNamingHelper.GetBindingName(wsdlBinding); newWsdlBindingEndpoint.Binding = CreateBinding(bindingEndpointContext, bindingQName); CallImportEndpoint(bindingEndpointContext); VerifyImportedWsdlBinding(wsdlBinding); importedBindings.Add(wsdlBindingQName, bindingEndpointContext); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Fx.IsFatal(e)) throw; WsdlImportException wie = WsdlImportException.Create(wsdlBinding, e); LogImportError(wsdlBinding, wie); if (errorBehavior == ErrorBehavior.RethrowExceptions) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(wie); else return null; } } return bindingEndpointContext; } ServiceEndpoint ImportWsdlPort(WsdlNS.Port wsdlPort, ErrorBehavior errorBehavior) { if (IsBlackListed(wsdlPort)) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateAlreadyFaultedException(wsdlPort)); ServiceEndpoint endpoint = null; if (!importedPorts.TryGetValue(wsdlPort, out endpoint)) { EnsureBeforeImportCalled(); try { WsdlNS.Binding wsdlBinding = this.wsdlDocuments.GetBinding(wsdlPort.Binding); WsdlEndpointConversionContext bindingEndpointContext = ImportWsdlBinding(wsdlBinding, ErrorBehavior.RethrowExceptions); WsdlEndpointConversionContext endpointContext; endpoint = new ServiceEndpoint(bindingEndpointContext.Endpoint.Contract); endpoint.Name = WsdlNamingHelper.GetEndpointName(wsdlPort).EncodedName; endpointContext = new WsdlEndpointConversionContext(bindingEndpointContext, endpoint, wsdlPort); if (WsdlPolicyReader.HasPolicy(wsdlPort)) { XmlQualifiedName bindingQName = WsdlNamingHelper.GetBindingName(wsdlPort); endpoint.Binding = CreateBinding(endpointContext, bindingQName); } else { endpoint.Binding = bindingEndpointContext.Endpoint.Binding; } CallImportEndpoint(endpointContext); VerifyImportedWsdlPort(wsdlPort); importedPorts.Add(wsdlPort, endpoint); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Fx.IsFatal(e)) throw; WsdlImportException wie = WsdlImportException.Create(wsdlPort, e); LogImportError(wsdlPort, wie); if (errorBehavior == ErrorBehavior.RethrowExceptions) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(wie); else return null; } } return endpoint; } static bool TryCreateMessageDescription(WsdlNS.OperationMessage wsdlOperationMessage, OperationDescription operationDescription, out MessageDescription messageDescription) { string actionUri = WSAddressingHelper.GetWsaActionUri(wsdlOperationMessage); MessageDirection direction; if (wsdlOperationMessage is WsdlNS.OperationInput) direction = MessageDirection.Input; else if (wsdlOperationMessage is WsdlNS.OperationOutput) direction = MessageDirection.Output; else { messageDescription = null; return false; } messageDescription = new MessageDescription(actionUri, direction); messageDescription.MessageName = WsdlNamingHelper.GetOperationMessageName(wsdlOperationMessage); messageDescription.XsdTypeName = wsdlOperationMessage.Message; operationDescription.Messages.Add(messageDescription); return true; } static bool TryCreateFaultDescription(WsdlNS.OperationFault wsdlOperationFault, OperationDescription operationDescription, out FaultDescription faultDescription) { if (string.IsNullOrEmpty(wsdlOperationFault.Name)) { faultDescription = null; return false; } string actionUri = WSAddressingHelper.GetWsaActionUri(wsdlOperationFault); faultDescription = new FaultDescription(actionUri); faultDescription.SetNameOnly(new XmlName(wsdlOperationFault.Name, true /*isEncoded*/)); operationDescription.Faults.Add(faultDescription); return true; } ContractDescription CreateContractDescription(WsdlNS.PortType wsdlPortType, XmlQualifiedName wsdlPortTypeQName) { ContractDescription contractDescription; XmlQualifiedName contractQName = WsdlNamingHelper.GetContractName(wsdlPortTypeQName); contractDescription = new ContractDescription(contractQName.Name, contractQName.Namespace); NetSessionHelper.SetSession(contractDescription, wsdlPortType); return contractDescription; } OperationDescription CreateOperationDescription(WsdlNS.PortType wsdlPortType, WsdlNS.Operation wsdlOperation, ContractDescription contract) { string operationName = WsdlNamingHelper.GetOperationName(wsdlOperation); OperationDescription operationDescription = new OperationDescription(operationName, contract); NetSessionHelper.SetInitiatingTerminating(operationDescription, wsdlOperation); contract.Operations.Add(operationDescription); return operationDescription; } Binding CreateBinding(WsdlEndpointConversionContext endpointContext, XmlQualifiedName bindingQName) { try { // either the wsdl:binding has already been imported or the wsdl:port has policy BindingElementCollection bindingElements = ImportPolicyFromWsdl(endpointContext); CustomBinding binding = new CustomBinding(bindingElements); // use decoded form to preserve the user-given friendly name binding.Name = NamingHelper.CodeName(bindingQName.Name); binding.Namespace = bindingQName.Namespace; return binding; } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Fx.IsFatal(e)) throw; throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(WsdlImportException.Create(endpointContext.WsdlBinding, e)); } } ContractDescription GetOrImportContractDescription(XmlQualifiedName wsdlPortTypeQName, out bool wasExistingContractDescription) { ContractDescription contractDescription; if (!TryFindExistingContract(wsdlPortTypeQName, out contractDescription)) { WsdlNS.PortType wsdlPortType = wsdlDocuments.GetPortType(wsdlPortTypeQName); contractDescription = ImportWsdlPortType(wsdlPortType, WsdlPortTypeImportOptions.IgnoreExistingContracts, ErrorBehavior.RethrowExceptions); wasExistingContractDescription = false; } wasExistingContractDescription = true; return contractDescription; } void ProcessMetadataDocuments(IEnumerable metadataSections) { foreach (MetadataSection doc in metadataSections) { try { if (doc.Metadata is MetadataReference || doc.Metadata is MetadataLocation) continue; if (doc.Dialect == MetadataSection.ServiceDescriptionDialect) { wsdlDocuments.Add(TryConvert(doc)); } if (doc.Dialect == MetadataSection.XmlSchemaDialect) { xmlSchemas.Add(TryConvert(doc)); } if (doc.Dialect == MetadataSection.PolicyDialect) { if (string.IsNullOrEmpty(doc.Identifier)) { LogImportWarning(SR.GetString(SR.PolicyDocumentMustHaveIdentifier)); } else { policyDocuments.Add(doc.Identifier, TryConvert(doc)); } } } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Fx.IsFatal(e)) throw; throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(doc.Identifier, e)); } } } T TryConvert(MetadataSection doc) { try { return ((T)doc.Metadata); } catch (InvalidCastException) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException( SR.GetString(SR.SFxBadMetadataDialect, doc.Identifier, doc.Dialect, typeof(T).FullName, doc.GetType().FullName))); } } bool TryFindExistingContract(XmlQualifiedName wsdlPortTypeQName, out ContractDescription existingContract) { XmlQualifiedName contractQName = WsdlNamingHelper.GetContractName(wsdlPortTypeQName); // Scan Known Contracts first because wsdl:portType may not be available if (this.KnownContracts.TryGetValue(contractQName, out existingContract)) return true; WsdlContractConversionContext contractContext; if (importedPortTypes.TryGetValue(wsdlPortTypeQName, out contractContext)) { existingContract = contractContext.Contract; return true; } return false; } void EnsureBeforeImportCalled() { if (!beforeImportCalled) { foreach (IWsdlImportExtension extension in this.wsdlExtensions) { try { extension.BeforeImport(this.wsdlDocuments, this.xmlSchemas, this.policyDocuments.Values); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { this.isFaulted = true; if (Fx.IsFatal(e)) throw; throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateBeforeImportExtensionException(extension, e)); } } beforeImportCalled = true; } } void CallImportContract(WsdlContractConversionContext contractConversionContext) { foreach (IWsdlImportExtension extension in this.wsdlExtensions) try { extension.ImportContract(this, contractConversionContext); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Fx.IsFatal(e)) throw; throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateExtensionException(extension, e)); } } void CallImportEndpoint(WsdlEndpointConversionContext endpointConversionContext) { foreach (IWsdlImportExtension extension in this.wsdlExtensions) try { extension.ImportEndpoint(this, endpointConversionContext); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Fx.IsFatal(e)) throw; throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateExtensionException(extension, e)); } } void VerifyImportedWsdlPortType(WsdlNS.PortType wsdlPortType) { VerifyImportedExtensions(wsdlPortType); foreach (WsdlNS.Operation wsdlOperation in wsdlPortType.Operations) { VerifyImportedExtensions(wsdlOperation); foreach (WsdlNS.OperationMessage wsdlOperationMessage in wsdlOperation.Messages) { VerifyImportedExtensions(wsdlOperationMessage); } foreach (WsdlNS.OperationMessage wsdlOperationMessage in wsdlOperation.Faults) { VerifyImportedExtensions(wsdlOperationMessage); } } } void VerifyImportedWsdlBinding(WsdlNS.Binding wsdlBinding) { VerifyImportedExtensions(wsdlBinding); foreach (WsdlNS.OperationBinding wsdlOperationBinding in wsdlBinding.Operations) { VerifyImportedExtensions(wsdlOperationBinding); if (wsdlOperationBinding.Input != null) { VerifyImportedExtensions(wsdlOperationBinding.Input); } if (wsdlOperationBinding.Output != null) { VerifyImportedExtensions(wsdlOperationBinding.Output); } foreach (WsdlNS.MessageBinding wsdlMessageBinding in wsdlOperationBinding.Faults) { VerifyImportedExtensions(wsdlMessageBinding); } } } void VerifyImportedWsdlPort(WsdlNS.Port wsdlPort) { VerifyImportedExtensions(wsdlPort); } void VerifyImportedExtensions(WsdlNS.NamedItem item) { foreach (object ext in item.Extensions) { if (item.Extensions.IsHandled(ext)) continue; XmlQualifiedName qName = GetUnhandledExtensionQName(ext, item); if (item.Extensions.IsRequired(ext) || IsNonSoapWsdl11BindingExtension(ext)) { string errorMsg = SR.GetString(SR.RequiredWSDLExtensionIgnored, qName.Name, qName.Namespace); WsdlImportException wie = WsdlImportException.Create(item, new InvalidOperationException(errorMsg)); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(wie); } else { string xPath = CreateXPathString(item); string errorMsg = SR.GetString(SR.OptionalWSDLExtensionIgnored, qName.Name, qName.Namespace, xPath); this.Errors.Add(new MetadataConversionError(errorMsg, true)); } } } static bool IsNonSoapWsdl11BindingExtension(object ext) { if (ext is WsdlNS.HttpAddressBinding || ext is WsdlNS.HttpBinding || ext is WsdlNS.HttpOperationBinding || ext is WsdlNS.HttpUrlEncodedBinding || ext is WsdlNS.HttpUrlReplacementBinding || ext is WsdlNS.MimeContentBinding || ext is WsdlNS.MimeMultipartRelatedBinding || ext is WsdlNS.MimePart || ext is WsdlNS.MimeTextBinding || ext is WsdlNS.MimeXmlBinding ) { return true; } return false; } XmlQualifiedName GetUnhandledExtensionQName(object extension, WsdlNS.NamedItem item) { XmlElement element = extension as XmlElement; if (element != null) { return new XmlQualifiedName(element.LocalName, element.NamespaceURI); } else if (extension is WsdlNS.ServiceDescriptionFormatExtension) { WsdlConfigNS.XmlFormatExtensionAttribute[] xfeAttributes = (WsdlConfigNS.XmlFormatExtensionAttribute[])ServiceReflector.GetCustomAttributes(extension.GetType(), typeof(WsdlConfigNS.XmlFormatExtensionAttribute), false); if (xfeAttributes.Length > 0) { return new XmlQualifiedName(xfeAttributes[0].ElementName, xfeAttributes[0].Namespace); } } WsdlImportException wie = WsdlImportException.Create(item, new InvalidOperationException(SR.GetString(SR.UnknownWSDLExtensionIgnored, extension.GetType().AssemblyQualifiedName))); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(wie); } internal static class Binding2DescriptionHelper { internal static OperationDescription FindOperationDescription(WsdlNS.OperationBinding wsdlOperationBinding, WsdlNS.ServiceDescriptionCollection wsdlDocuments, WsdlEndpointConversionContext endpointContext) { OperationDescription operation; if (endpointContext.ContractConversionContext != null) { WsdlNS.Operation wsdlOperation = FindWsdlOperation(wsdlOperationBinding, wsdlDocuments); operation = endpointContext.ContractConversionContext.GetOperationDescription(wsdlOperation); } else { operation = FindOperationDescription(endpointContext.Endpoint.Contract, wsdlOperationBinding); } return operation; } internal static WsdlNS.MessageBinding FindMessageBinding(WsdlNS.OperationBinding wsdlOperationBinding, MessageDescription message) { WsdlNS.MessageBinding wsdlMessageBinding; if (message.Direction == MessageDirection.Input) { wsdlMessageBinding = wsdlOperationBinding.Input; } else { wsdlMessageBinding = wsdlOperationBinding.Output; } return wsdlMessageBinding; } internal static WsdlNS.FaultBinding FindFaultBinding(WsdlNS.OperationBinding wsdlOperationBinding, FaultDescription fault) { foreach (WsdlNS.FaultBinding faultBinding in wsdlOperationBinding.Faults) if (faultBinding.Name == fault.Name) return faultBinding; return null; } static WsdlNS.Operation FindWsdlOperation(WsdlNS.OperationBinding wsdlOperationBinding, WsdlNS.ServiceDescriptionCollection wsdlDocuments) { WsdlNS.PortType wsdlPortType = wsdlDocuments.GetPortType(wsdlOperationBinding.Binding.Type); string wsdlOperationBindingName = wsdlOperationBinding.Name; if (wsdlOperationBindingName == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidWsdlBindingOpNoName, wsdlOperationBinding.Binding.Name))); } WsdlNS.Operation partialMatchResult = null; foreach (WsdlNS.Operation wsdlOperation in wsdlPortType.Operations) { switch (Match(wsdlOperationBinding, wsdlOperation)) { case MatchResult.None: break; case MatchResult.Partial: partialMatchResult = wsdlOperation; break; case MatchResult.Exact: return wsdlOperation; default: Fx.AssertAndFailFast("Unexpected MatchResult value."); break; } } if (partialMatchResult != null) { return partialMatchResult; } else { //unable to find wsdloperation for wsdlOperationBinding, invalid wsdl binding throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidWsdlBindingOpMismatch2, wsdlOperationBinding.Binding.Name, wsdlOperationBinding.Name))); } } internal enum MatchResult { None, Partial, Exact } internal static MatchResult Match(WsdlNS.OperationBinding wsdlOperationBinding, WsdlNS.Operation wsdlOperation) { // This method checks if there is a match based on Names, between the specified OperationBinding and Operation. // When searching for the Operation associated with an OperationBinding, we need to return an exact match if possible, // or a partial match otherwise (when some of the Names are null). // Bug 16833 @ CSDMain requires that partial matches are allowed, while the TFS bug 477838 requires that exact matches are done (when possible). if (wsdlOperationBinding.Name != wsdlOperation.Name) { return MatchResult.None; } MatchResult result = MatchResult.Exact; foreach (WsdlNS.OperationMessage wsdlOperationMessage in wsdlOperation.Messages) { WsdlNS.MessageBinding wsdlMessageBinding; if (wsdlOperationMessage is WsdlNS.OperationInput) wsdlMessageBinding = wsdlOperationBinding.Input; else wsdlMessageBinding = wsdlOperationBinding.Output; if (wsdlMessageBinding == null) { return MatchResult.None; } switch (MatchOperationParameterName(wsdlMessageBinding, wsdlOperationMessage)) { case MatchResult.None: return MatchResult.None; case MatchResult.Partial: result = MatchResult.Partial; break; } } return result; } static MatchResult MatchOperationParameterName(WsdlNS.MessageBinding wsdlMessageBinding, WsdlNS.OperationMessage wsdlOperationMessage) { string wsdlOperationMessageName = wsdlOperationMessage.Name; string wsdlMessageBindingName = wsdlMessageBinding.Name; if (wsdlOperationMessageName == wsdlMessageBindingName) { return MatchResult.Exact; } string wsdlOperationMessageDecodedName = WsdlNamingHelper.GetOperationMessageName(wsdlOperationMessage).DecodedName; if ((wsdlOperationMessageName == null) && (wsdlMessageBindingName == wsdlOperationMessageDecodedName)) { return MatchResult.Partial; } else if ((wsdlMessageBindingName == null) && (wsdlOperationMessageName == wsdlOperationMessageDecodedName)) { return MatchResult.Partial; } else { return MatchResult.None; } } static OperationDescription FindOperationDescription(ContractDescription contract, WsdlNS.OperationBinding wsdlOperationBinding) { foreach (OperationDescription operationDescription in contract.Operations) { if (CompareOperations(operationDescription, contract, wsdlOperationBinding)) return operationDescription; } throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.UnableToLocateOperation2, wsdlOperationBinding.Name, contract.Name))); } static bool CompareOperations(OperationDescription operationDescription, ContractDescription parentContractDescription, WsdlNS.OperationBinding wsdlOperationBinding) { string wsdlOperationName = WsdlExporter.WsdlNamingHelper.GetWsdlOperationName(operationDescription, parentContractDescription); if (wsdlOperationName != wsdlOperationBinding.Name) return false; if (operationDescription.Messages.Count > 2) return false; // Either both have output message or neither have an output message; if (FindMessage(operationDescription.Messages, MessageDirection.Output) != (wsdlOperationBinding.Output != null)) return false; // Either both have output message or neither have an output message; if (FindMessage(operationDescription.Messages, MessageDirection.Input) != (wsdlOperationBinding.Input != null)) return false; return true; } private static bool FindMessage(MessageDescriptionCollection messageDescriptionCollection, MessageDirection transferDirection) { foreach (MessageDescription message in messageDescriptionCollection) if (message.Direction == transferDirection) return true; return false; } } internal static class WSAddressingHelper { internal static string GetWsaActionUri(WsdlNS.OperationMessage wsdlOperationMessage) { string actionUri = FindWsaActionAttribute(wsdlOperationMessage); return (actionUri == null) ? CreateDefaultWsaActionUri(wsdlOperationMessage) : actionUri; } internal static string FindWsaActionAttribute(WsdlNS.OperationMessage wsdlOperationMessage) { XmlAttribute[] attributes = wsdlOperationMessage.ExtensibleAttributes; if (attributes != null && attributes.Length > 0) { foreach (XmlAttribute attribute in attributes) { if ((attribute.NamespaceURI == MetadataStrings.AddressingWsdl.NamespaceUri || attribute.NamespaceURI == MetadataStrings.AddressingMetadata.NamespaceUri) && attribute.LocalName == MetadataStrings.AddressingMetadata.Action) { return attribute.Value; } } } return null; } static string CreateDefaultWsaActionUri(WsdlNS.OperationMessage wsdlOperationMessage) { if (wsdlOperationMessage is WsdlNS.OperationFault) return AddressingVersion.WSAddressing10.DefaultFaultAction; // We figure out default action. All specifications' rules below are the same. // Using [WSDL Binding W3C Working Draft 13 April 2005] Section 3.3 // Using [WSDL Binding W3C Candidate Recommendation 29 May 2006] Section 4.4.4 // Using [Metadata W3C Working Draft 13 16 May 2007] Section 4.4.4 string ns = wsdlOperationMessage.Operation.PortType.ServiceDescription.TargetNamespace ?? string.Empty; string portTypeName = wsdlOperationMessage.Operation.PortType.Name; XmlName operationMessageName = WsdlNamingHelper.GetOperationMessageName(wsdlOperationMessage); string delimiter = ns.StartsWith("urn:", StringComparison.OrdinalIgnoreCase) ? ":" : "/"; string baseActionUri = ns.EndsWith(delimiter, StringComparison.OrdinalIgnoreCase) ? ns : ns + delimiter; string actionUri = string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}{3}", baseActionUri, portTypeName, delimiter, operationMessageName.EncodedName); return actionUri; } internal static EndpointAddress ImportAddress(WsdlNS.Port wsdlPort) { //Try to read Endpoint Address from WsdlPort if (wsdlPort != null) { XmlElement addressing10Element = wsdlPort.Extensions.Find(AddressingStrings.EndpointReference, Addressing10Strings.Namespace); XmlElement addressing200408Element = wsdlPort.Extensions.Find(AddressingStrings.EndpointReference, Addressing200408Strings.Namespace); WsdlNS.SoapAddressBinding soapAddressBinding = (WsdlNS.SoapAddressBinding)wsdlPort.Extensions.Find(typeof(WsdlNS.SoapAddressBinding)); // if (addressing10Element != null) { return EndpointAddress.ReadFrom(AddressingVersion.WSAddressing10, new XmlNodeReader(addressing10Element)); } if (addressing200408Element != null) { return EndpointAddress.ReadFrom(AddressingVersion.WSAddressingAugust2004, new XmlNodeReader(addressing200408Element)); } else if (soapAddressBinding != null) { return new EndpointAddress(soapAddressBinding.Location); } } return null; } internal static AddressingVersion FindAddressingVersion(PolicyConversionContext policyContext) { if (PolicyConversionContext.FindAssertion(policyContext.GetBindingAssertions(), MetadataStrings.Addressing10.WsdlBindingPolicy.UsingAddressing, MetadataStrings.Addressing10.WsdlBindingPolicy.NamespaceUri, true /*remove*/) != null) { return AddressingVersion.WSAddressing10; } else if (PolicyConversionContext.FindAssertion(policyContext.GetBindingAssertions(), MetadataStrings.Addressing10.MetadataPolicy.Addressing, MetadataStrings.Addressing10.MetadataPolicy.NamespaceUri, true /*remove*/) != null) { return AddressingVersion.WSAddressing10; } else if (PolicyConversionContext.FindAssertion(policyContext.GetBindingAssertions(), MetadataStrings.Addressing200408.Policy.UsingAddressing, MetadataStrings.Addressing200408.Policy.NamespaceUri, true /*remove*/) != null) { return AddressingVersion.WSAddressingAugust2004; } else { return AddressingVersion.None; } } internal static SupportedAddressingMode DetermineSupportedAddressingMode(MetadataImporter importer, PolicyConversionContext context) { // Do not remove this assertion - the message encoding binding element importer owns it. XmlElement addressingAssertion = PolicyConversionContext.FindAssertion(context.GetBindingAssertions(), MetadataStrings.Addressing10.MetadataPolicy.Addressing, MetadataStrings.Addressing10.MetadataPolicy.NamespaceUri, false); if (addressingAssertion != null) { XmlElement policyElement = null; foreach (XmlNode node in addressingAssertion.ChildNodes) { if (node is XmlElement && MetadataSection.IsPolicyElement((XmlElement)node)) { policyElement = (XmlElement)node; break; } } if (policyElement == null) { string message = SR.GetString(SR.ElementRequired, MetadataStrings.Addressing10.MetadataPolicy.Prefix, MetadataStrings.Addressing10.MetadataPolicy.Addressing, MetadataStrings.WSPolicy.Prefix, MetadataStrings.WSPolicy.Elements.Policy); importer.Errors.Add(new MetadataConversionError(message, false)); return SupportedAddressingMode.Anonymous; } IEnumerable> alternatives = importer.NormalizePolicy(new XmlElement[] { policyElement }); foreach (IEnumerable alternative in alternatives) { foreach (XmlElement element in alternative) { if (element.NamespaceURI == MetadataStrings.Addressing10.MetadataPolicy.NamespaceUri) { if (element.LocalName == MetadataStrings.Addressing10.MetadataPolicy.NonAnonymousResponses) { return SupportedAddressingMode.NonAnonymous; } else if (element.LocalName == MetadataStrings.Addressing10.MetadataPolicy.AnonymousResponses) { return SupportedAddressingMode.Anonymous; } } } } } return SupportedAddressingMode.Anonymous; } } static class WsdlNamingHelper { internal static XmlQualifiedName GetBindingName(WsdlNS.Binding wsdlBinding) { XmlName xmlName = new XmlName(wsdlBinding.Name, true /*isEncoded*/); return new XmlQualifiedName(xmlName.EncodedName, wsdlBinding.ServiceDescription.TargetNamespace); } internal static XmlQualifiedName GetBindingName(WsdlNS.Port wsdlPort) { // Microsoft: composing names have potential problem of generating name that looks like an encoded name, consider avoiding '_' XmlName xmlName = new XmlName(string.Format(CultureInfo.InvariantCulture, "{0}_{1}", wsdlPort.Service.Name, wsdlPort.Name), true /*isEncoded*/); return new XmlQualifiedName(xmlName.EncodedName, wsdlPort.Service.ServiceDescription.TargetNamespace); } internal static XmlName GetEndpointName(WsdlNS.Port wsdlPort) { return new XmlName(wsdlPort.Name, true /*isEncoded*/); } internal static XmlQualifiedName GetContractName(XmlQualifiedName wsdlPortTypeQName) { return wsdlPortTypeQName; } internal static string GetOperationName(WsdlNS.Operation wsdlOperation) { return wsdlOperation.Name; } internal static XmlName GetOperationMessageName(WsdlNS.OperationMessage wsdlOperationMessage) { string messageName = null; if (!string.IsNullOrEmpty(wsdlOperationMessage.Name)) { messageName = wsdlOperationMessage.Name; } else if (wsdlOperationMessage.Operation.Messages.Count == 1) { messageName = wsdlOperationMessage.Operation.Name; } else if (wsdlOperationMessage.Operation.Messages.IndexOf(wsdlOperationMessage) == 0) { if (wsdlOperationMessage is WsdlNS.OperationInput) messageName = wsdlOperationMessage.Operation.Name + "Request"; else if (wsdlOperationMessage is WsdlNS.OperationOutput) messageName = wsdlOperationMessage.Operation.Name + "Solicit"; } else if (wsdlOperationMessage.Operation.Messages.IndexOf(wsdlOperationMessage) == 1) { messageName = wsdlOperationMessage.Operation.Name + "Response"; } else { // Microsoft: why this is an Assert, and not an exception? Fx.Assert("Unsupported WSDL OM (More than 2 OperationMessages encountered in an Operation or WsdlOM is invalid)"); } // names the come from service description documents have to be valid NCNames; XmlName.ctor will validate. return new XmlName(messageName, true /*isEncoded*/); } } internal static class NetSessionHelper { internal static void SetInitiatingTerminating(OperationDescription operationDescription, WsdlNS.Operation wsdlOperation) { XmlAttribute isInitiating = FindAttribute(wsdlOperation.ExtensibleAttributes, WsdlExporter.NetSessionHelper.IsInitiating, WsdlExporter.NetSessionHelper.NamespaceUri); if (isInitiating != null) { if (isInitiating.Value == WsdlExporter.NetSessionHelper.True) { operationDescription.IsInitiating = true; } if (isInitiating.Value == WsdlExporter.NetSessionHelper.False) { operationDescription.IsInitiating = false; } } XmlAttribute isTerminating = FindAttribute(wsdlOperation.ExtensibleAttributes, WsdlExporter.NetSessionHelper.IsTerminating, WsdlExporter.NetSessionHelper.NamespaceUri); if (isTerminating != null) { if (isTerminating.Value == WsdlExporter.NetSessionHelper.True) { operationDescription.IsTerminating = true; } if (isTerminating.Value == WsdlExporter.NetSessionHelper.False) { operationDescription.IsTerminating = false; } } } internal static void SetSession(ContractDescription contractDescription, WsdlNS.PortType wsdlPortType) { XmlAttribute usingSession = FindAttribute(wsdlPortType.ExtensibleAttributes, WsdlExporter.NetSessionHelper.UsingSession, WsdlExporter.NetSessionHelper.NamespaceUri); if (usingSession != null) { if (usingSession.Value == WsdlExporter.NetSessionHelper.True) { contractDescription.SessionMode = SessionMode.Required; } if (usingSession.Value == WsdlExporter.NetSessionHelper.False) { contractDescription.SessionMode = SessionMode.NotAllowed; } } } static XmlAttribute FindAttribute(XmlAttribute[] attributes, string localName, string ns) { if (attributes != null) { foreach (XmlAttribute attribute in attributes) { if (attribute.LocalName == localName && attribute.NamespaceURI == ns) { return attribute; } } } return null; } } internal static class SoapInPolicyWorkaroundHelper { public const string soapTransportUriKey = "TransportBindingElementImporter.TransportUri"; const string workaroundNS = NamingHelper.DefaultNamespace + "temporaryworkaround"; const string bindingAttrName = "bindingName"; const string bindingAttrNamespace = "bindingNamespace"; static XmlDocument xmlDocument; static public void InsertAdHocPolicy(WsdlNS.Binding wsdlBinding, string value, string key) { XmlQualifiedName wsdlBindingQName = new XmlQualifiedName(wsdlBinding.Name, wsdlBinding.ServiceDescription.TargetNamespace); string id = AddPolicyUri(wsdlBinding, key); InsertPolicy(key, id, wsdlBinding.ServiceDescription, value, wsdlBindingQName); } static public string FindAdHocTransportPolicy(PolicyConversionContext policyContext, out XmlQualifiedName wsdlBindingQName) { return FindAdHocPolicy(policyContext, soapTransportUriKey, out wsdlBindingQName); } static public string FindAdHocPolicy(PolicyConversionContext policyContext, string key, out XmlQualifiedName wsdlBindingQName) { if (policyContext == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("policyContext"); XmlElement policy = PolicyConversionContext.FindAssertion(policyContext.GetBindingAssertions(), key, workaroundNS, true); if (policy != null) { wsdlBindingQName = new XmlQualifiedName(policy.Attributes[bindingAttrName].Value, policy.Attributes[bindingAttrNamespace].Value); return policy.InnerText; } else { wsdlBindingQName = null; return null; } } static string AddPolicyUri(WsdlNS.Binding wsdlBinding, string name) { string policyUris = ReadPolicyUris(wsdlBinding); string id = string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}_{1}_BindingAdHocPolicy", wsdlBinding.Name, name); string newPolicyUris = string.Format(System.Globalization.CultureInfo.InvariantCulture, "#{0} {1}", id, policyUris).Trim(); WritePolicyUris(wsdlBinding, newPolicyUris); return id; } static XmlDocument XmlDoc { get { if (xmlDocument == null) { NameTable nameTable = new NameTable(); nameTable.Add(MetadataStrings.WSPolicy.Elements.Policy); nameTable.Add(MetadataStrings.WSPolicy.Elements.All); nameTable.Add(MetadataStrings.WSPolicy.Elements.ExactlyOne); nameTable.Add(MetadataStrings.WSPolicy.Attributes.PolicyURIs); nameTable.Add(MetadataStrings.Wsu.Attributes.Id); xmlDocument = new XmlDocument(nameTable); } return xmlDocument; } } static void WritePolicyUris(WsdlNS.DocumentableItem item, string newValue) { int i; XmlAttribute[] attributes = item.ExtensibleAttributes; if (attributes != null && attributes.Length > 0) { foreach (XmlAttribute attribute in attributes) if (MetadataImporter.PolicyHelper.IsPolicyURIs(attribute)) { attribute.Value = newValue; return; } // Need to extend i = attributes.Length; Array.Resize(ref attributes, i + 1); } else { //Need to create i = 0; attributes = new XmlAttribute[1]; } attributes[i] = CreatePolicyURIsAttribute(newValue); item.ExtensibleAttributes = attributes; } static XmlAttribute CreatePolicyURIsAttribute(string value) { XmlAttribute attribute = XmlDoc.CreateAttribute(MetadataStrings.WSPolicy.Prefix, MetadataStrings.WSPolicy.Attributes.PolicyURIs, MetadataStrings.WSPolicy.NamespaceUri); attribute.Value = value; return attribute; } static string ReadPolicyUris(WsdlNS.DocumentableItem item) { XmlAttribute[] attributes = item.ExtensibleAttributes; if (attributes != null && attributes.Length > 0) { foreach (XmlAttribute attribute in attributes) { if (MetadataImporter.PolicyHelper.IsPolicyURIs(attribute)) { return attribute.Value; } } } return string.Empty; } static void InsertPolicy(string key, string id, WsdlNS.ServiceDescription policyWsdl, string value, XmlQualifiedName wsdlBindingQName) { // Create [wsp:Policy] XmlElement policyElement = CreatePolicyElement(key, value, wsdlBindingQName); //Create [wsp:Policy/@wsu:Id] XmlAttribute idAttribute = XmlDoc.CreateAttribute(MetadataStrings.Wsu.Prefix, MetadataStrings.Wsu.Attributes.Id, MetadataStrings.Wsu.NamespaceUri); idAttribute.Value = id; policyElement.SetAttributeNode(idAttribute); // Add wsp:Policy To WSDL policyWsdl.Extensions.Add(policyElement); } static XmlElement CreatePolicyElement(string elementName, string value, XmlQualifiedName wsdlBindingQName) { // Create [wsp:Policy] XmlElement policyElement = XmlDoc.CreateElement(MetadataStrings.WSPolicy.Prefix, MetadataStrings.WSPolicy.Elements.Policy, MetadataStrings.WSPolicy.NamespaceUri); // Create [wsp:Policy/wsp:ExactlyOne] XmlElement exactlyOneElement = XmlDoc.CreateElement(MetadataStrings.WSPolicy.Prefix, MetadataStrings.WSPolicy.Elements.ExactlyOne, MetadataStrings.WSPolicy.NamespaceUri); policyElement.AppendChild(exactlyOneElement); // Create [wsp:Policy/wsp:ExactlyOne/wsp:All] XmlElement allElement = XmlDoc.CreateElement(MetadataStrings.WSPolicy.Prefix, MetadataStrings.WSPolicy.Elements.All, MetadataStrings.WSPolicy.NamespaceUri); exactlyOneElement.AppendChild(allElement); // Add [wsp:Policy/wsp:ExactlyOne/wsp:All/*] XmlElement workaroundElement = xmlDocument.CreateElement(elementName, workaroundNS); workaroundElement.InnerText = value; XmlAttribute bindingName = xmlDocument.CreateAttribute(bindingAttrName); bindingName.Value = wsdlBindingQName.Name; workaroundElement.Attributes.Append(bindingName); XmlAttribute bindingNamespace = xmlDocument.CreateAttribute(bindingAttrNamespace); bindingNamespace.Value = wsdlBindingQName.Namespace; workaroundElement.Attributes.Append(bindingNamespace); workaroundElement.Attributes.Append(bindingNamespace); allElement.AppendChild(workaroundElement); return policyElement; } internal static void InsertAdHocTransportPolicy(WsdlNS.ServiceDescriptionCollection wsdlDocuments) { foreach (WsdlNS.ServiceDescription wsdl in wsdlDocuments) if (wsdl != null) { foreach (WsdlNS.Binding wsdlBinding in wsdl.Bindings) { if (WsdlImporter.WsdlPolicyReader.ContainsPolicy(wsdlBinding)) { WsdlNS.SoapBinding soapBinding = (WsdlNS.SoapBinding)wsdlBinding.Extensions.Find(typeof(WsdlNS.SoapBinding)); if (soapBinding != null) WsdlImporter .SoapInPolicyWorkaroundHelper .InsertAdHocPolicy(wsdlBinding, soapBinding.Transport, soapTransportUriKey); } } } } } IEnumerable FindBindingsForPortType(WsdlNS.PortType wsdlPortType) { foreach (WsdlNS.Binding wsdlBinding in GetAllBindings()) { if (wsdlBinding.Type.Name == wsdlPortType.Name && wsdlBinding.Type.Namespace == wsdlPortType.ServiceDescription.TargetNamespace) yield return wsdlBinding; } } IEnumerable FindBindingsForContract(ContractDescription contract) { XmlQualifiedName qName = WsdlExporter.WsdlNamingHelper.GetPortTypeQName(contract); foreach (WsdlNS.Binding wsdlBinding in GetAllBindings()) { if (wsdlBinding.Type.Name == qName.Name && wsdlBinding.Type.Namespace == qName.Namespace) yield return wsdlBinding; } } IEnumerable FindPortsForBinding(WsdlNS.Binding binding) { foreach (WsdlNS.Port wsdlPort in GetAllPorts()) { if (wsdlPort.Binding.Name == binding.Name && wsdlPort.Binding.Namespace == binding.ServiceDescription.TargetNamespace) yield return wsdlPort; } } IEnumerable GetAllBindings() { foreach (WsdlNS.ServiceDescription wsdl in this.WsdlDocuments) { foreach (WsdlNS.Binding wsdlBinding in wsdl.Bindings) { yield return wsdlBinding; } } } IEnumerable GetAllPorts() { foreach (WsdlNS.ServiceDescription wsdl in this.WsdlDocuments) { foreach (WsdlNS.Service wsdlService in wsdl.Services) { foreach (WsdlNS.Port wsdlPort in wsdlService.Ports) { yield return wsdlPort; } } } } [Fx.Tag.SecurityNote(Critical = "Uses ClientSection.UnsafeGetSection to get config in PT.", Safe = "Does not leak config object, just picks up extensions.")] [SecuritySafeCritical] static Collection LoadWsdlExtensionsFromConfig() { return ConfigNS.ClientSection.UnsafeGetSection().Metadata.LoadWsdlImportExtensions(); } internal static IEnumerable CreateMetadataDocuments(WsdlNS.ServiceDescriptionCollection wsdlDocuments, XmlSchemaSet xmlSchemas, IEnumerable policyDocuments) { if (wsdlDocuments != null) foreach (WsdlNS.ServiceDescription wsdl in wsdlDocuments) yield return MetadataSection.CreateFromServiceDescription(wsdl); if (xmlSchemas != null) foreach (XmlSchema schema in xmlSchemas.Schemas()) yield return MetadataSection.CreateFromSchema(schema); if (policyDocuments != null) foreach (XmlElement policyDocument in policyDocuments) yield return MetadataSection.CreateFromPolicy(policyDocument, null); } BindingElementCollection ImportPolicyFromWsdl(WsdlEndpointConversionContext endpointContext) { PolicyAlternatives policyAlternatives = this.PolicyReader.GetPolicyAlternatives(endpointContext); IEnumerable policyContexts = GetPolicyConversionContextEnumerator(endpointContext.Endpoint, policyAlternatives, this.Quotas); PolicyConversionContext firstContext = null; StringBuilder unImportedPolicyMessage = null; int policyConversionContextsSeen = 0; //limit on the number of alternatives that we'll evaluate foreach (PolicyConversionContext policyConversionContext in policyContexts) { if (firstContext == null) firstContext = policyConversionContext; if (this.TryImportPolicy(policyConversionContext)) { return policyConversionContext.BindingElements; } else { AppendUnImportedPolicyErrorMessage(ref unImportedPolicyMessage, endpointContext, policyConversionContext); } if (++policyConversionContextsSeen >= this.Quotas.MaxPolicyConversionContexts) { break; } } // we failed to import policy for all PolicyConversionContexts, lets pick one context (the first one) // and wrap all unprocessed assertion in UnrecognizedAssertionsBindingElement if (firstContext != null) { #pragma warning suppress 56506 firstContext.BindingElements.Insert(0, CollectUnrecognizedAssertions(firstContext, endpointContext)); LogImportWarning(unImportedPolicyMessage.ToString()); return firstContext.BindingElements; } // Consider: a /verbose option for svcutil... if (endpointContext.WsdlPort != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(WsdlImportException.Create(endpointContext.WsdlPort, new InvalidOperationException(SR.GetString(SR.NoUsablePolicyAssertions)))); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(WsdlImportException.Create(endpointContext.WsdlBinding, new InvalidOperationException(SR.GetString(SR.NoUsablePolicyAssertions)))); } } static UnrecognizedAssertionsBindingElement CollectUnrecognizedAssertions(PolicyConversionContext policyContext, WsdlEndpointConversionContext endpointContext) { XmlQualifiedName bindingQName = new XmlQualifiedName(endpointContext.WsdlBinding.Name, endpointContext.WsdlBinding.ServiceDescription.TargetNamespace); UnrecognizedAssertionsBindingElement unknownBindingElement = new UnrecognizedAssertionsBindingElement(bindingQName, policyContext.GetBindingAssertions()); foreach (OperationDescription operation in policyContext.Contract.Operations) { if (policyContext.GetOperationBindingAssertions(operation).Count != 0) { unknownBindingElement.Add(operation, policyContext.GetOperationBindingAssertions(operation)); } foreach (MessageDescription message in operation.Messages) { if (policyContext.GetMessageBindingAssertions(message).Count != 0) { unknownBindingElement.Add(message, policyContext.GetMessageBindingAssertions(message)); } } } return unknownBindingElement; } static void AppendUnImportedPolicyErrorMessage(ref StringBuilder unImportedPolicyMessage, WsdlEndpointConversionContext endpointContext, PolicyConversionContext policyContext) { if (unImportedPolicyMessage == null) { unImportedPolicyMessage = new StringBuilder(SR.GetString(SR.UnabletoImportPolicy)); } else { unImportedPolicyMessage.AppendLine(); } if (policyContext.GetBindingAssertions().Count != 0) AddUnImportedPolicyString(unImportedPolicyMessage, endpointContext.WsdlBinding, policyContext.GetBindingAssertions()); foreach (OperationDescription operation in policyContext.Contract.Operations) { if (policyContext.GetOperationBindingAssertions(operation).Count != 0) { AddUnImportedPolicyString(unImportedPolicyMessage, endpointContext.GetOperationBinding(operation), policyContext.GetOperationBindingAssertions(operation)); } foreach (MessageDescription message in operation.Messages) { if (policyContext.GetMessageBindingAssertions(message).Count != 0) { AddUnImportedPolicyString(unImportedPolicyMessage, endpointContext.GetMessageBinding(message), policyContext.GetMessageBindingAssertions(message)); } } } } static void AddUnImportedPolicyString(StringBuilder stringBuilder, WsdlNS.NamedItem item, IEnumerable unimportdPolicy) { stringBuilder.AppendLine(SR.GetString(SR.UnImportedAssertionList, CreateXPathString(item))); // do not putput duplicated assetions Dictionary unique = new Dictionary(); int uniqueAsserions = 0; foreach (XmlElement element in unimportdPolicy) { if (unique.ContainsKey(element)) continue; unique.Add(element, element); uniqueAsserions++; if (uniqueAsserions > 128) { stringBuilder.Append(".."); stringBuilder.AppendLine(); break; } WriteElement(element, stringBuilder); } } static void WriteElement(XmlElement element, StringBuilder stringBuilder) { stringBuilder.Append(" <"); stringBuilder.Append(element.Name); if (!string.IsNullOrEmpty(element.NamespaceURI)) { stringBuilder.Append(' '); stringBuilder.Append("xmlns"); if (!string.IsNullOrEmpty(element.Prefix)) { stringBuilder.Append(':'); stringBuilder.Append(element.Prefix); } stringBuilder.Append('='); stringBuilder.Append('\''); stringBuilder.Append(element.NamespaceURI); stringBuilder.Append('\''); } stringBuilder.Append(">..'); stringBuilder.AppendLine(); } const string xPathDocumentFormatString = "//wsdl:definitions[@targetNamespace='{0}']"; const string xPathItemSubFormatString = "/wsdl:{0}"; const string xPathNamedItemSubFormatString = xPathItemSubFormatString + "[@name='{1}']"; static string GetElementName(WsdlNS.NamedItem item) { if (item is WsdlNS.PortType) return "wsdl:portType"; else if (item is WsdlNS.Binding) return "wsdl:binding"; else if (item is WsdlNS.ServiceDescription) return "wsdl:definitions"; else if (item is WsdlNS.Service) return "wsdl:service"; else if (item is WsdlNS.Message) return "wsdl:message"; else if (item is WsdlNS.Operation) return "wsdl:operation"; else if (item is WsdlNS.Port) return "wsdl:port"; else { Fx.Assert("GetElementName Method should be updated to support " + item.GetType()); return null; } } static string CreateXPathString(WsdlNS.NamedItem item) { if (item == null) return SR.GetString(SR.XPathUnavailable); string nameValue = item.Name; string localName; string wsdlNs; string rest = string.Empty; string itemPath = string.Empty; GetXPathParameters(item, out wsdlNs, out localName, ref nameValue, ref rest); string documentPath = string.Format(CultureInfo.InvariantCulture, xPathDocumentFormatString, wsdlNs); if (localName != null) { itemPath = string.Format(CultureInfo.InvariantCulture, xPathNamedItemSubFormatString, localName, nameValue); } Fx.Assert(rest != null, "GetXPathParameters Method should never set rest to null. this happened for: " + item.GetType()); return documentPath + itemPath + rest; } static void GetXPathParameters(WsdlNS.NamedItem item, out string wsdlNs, out string localName, ref string nameValue, ref string rest) { if (item is WsdlNS.ServiceDescription) { localName = null; wsdlNs = ((WsdlNS.ServiceDescription)item).TargetNamespace ?? String.Empty; } if (item is WsdlNS.PortType) { localName = "portType"; wsdlNs = ((WsdlNS.PortType)item).ServiceDescription.TargetNamespace ?? String.Empty; } else if (item is WsdlNS.Binding) { localName = "binding"; wsdlNs = ((WsdlNS.Binding)item).ServiceDescription.TargetNamespace ?? String.Empty; } else if (item is WsdlNS.ServiceDescription) { localName = "definitions"; wsdlNs = ((WsdlNS.ServiceDescription)item).TargetNamespace ?? String.Empty; } else if (item is WsdlNS.Service) { localName = "service"; wsdlNs = ((WsdlNS.Service)item).ServiceDescription.TargetNamespace ?? String.Empty; } else if (item is WsdlNS.Message) { localName = "message"; wsdlNs = ((WsdlNS.Message)item).ServiceDescription.TargetNamespace ?? String.Empty; } else if (item is WsdlNS.Port) { WsdlNS.Service wsdlService = ((WsdlNS.Port)item).Service; localName = "service"; nameValue = wsdlService.Name; wsdlNs = wsdlService.ServiceDescription.TargetNamespace ?? String.Empty; rest = string.Format(CultureInfo.InvariantCulture, xPathNamedItemSubFormatString, "port", item.Name); } else if (item is WsdlNS.Operation) { WsdlNS.PortType wsdlPortType = ((WsdlNS.Operation)item).PortType; localName = "portType"; nameValue = wsdlPortType.Name; wsdlNs = wsdlPortType.ServiceDescription.TargetNamespace ?? String.Empty; rest = string.Format(CultureInfo.InvariantCulture, xPathNamedItemSubFormatString, "operation", item.Name); } else if (item is WsdlNS.OperationBinding) { WsdlNS.OperationBinding wsdlOperationBinding = ((WsdlNS.OperationBinding)item); localName = "binding"; nameValue = wsdlOperationBinding.Binding.Name; wsdlNs = wsdlOperationBinding.Binding.ServiceDescription.TargetNamespace ?? String.Empty; rest = string.Format(CultureInfo.InvariantCulture, xPathNamedItemSubFormatString, "operation", item.Name); } else if (item is WsdlNS.MessageBinding) { localName = "binding"; WsdlNS.OperationBinding wsdlOperationBinding = ((WsdlNS.MessageBinding)item).OperationBinding; wsdlNs = wsdlOperationBinding.Binding.ServiceDescription.TargetNamespace ?? String.Empty; nameValue = wsdlOperationBinding.Binding.Name; string messageName = item.Name; string messageTag = string.Empty; if (item is WsdlNS.InputBinding) messageTag = "input"; else if (item is WsdlNS.OutputBinding) messageTag = "output"; else if (item is WsdlNS.FaultBinding) messageTag = "fault"; else Fx.Assert("Unsupported WSDL OM: unknown WsdlNS.MessageBinding: " + item.GetType()); rest = string.Format(CultureInfo.InvariantCulture, xPathNamedItemSubFormatString, "operation", wsdlOperationBinding.Name); if (string.IsNullOrEmpty(messageName)) rest += string.Format(CultureInfo.InvariantCulture, xPathItemSubFormatString, messageTag); else rest += string.Format(CultureInfo.InvariantCulture, xPathNamedItemSubFormatString, messageTag, messageName); } else { Fx.Assert("GetXPathParameters Method should be updated to support " + item.GetType()); localName = null; wsdlNs = null; } } void LogImportWarning(string warningMessage) { if (warnings.ContainsKey(warningMessage)) return; if (warnings.Count >= 1024) warnings.Clear(); warnings.Add(warningMessage, warningMessage); this.Errors.Add(new MetadataConversionError(warningMessage, true)); } void LogImportError(WsdlNS.NamedItem item, WsdlImportException wie) { string errormessage; if (wie.InnerException != null && (wie.InnerException is WsdlImportException)) { WsdlImportException wieInner = wie.InnerException as WsdlImportException; string dependencyMessage = SR.GetString(SR.WsdlImportErrorDependencyDetail, GetElementName(wieInner.SourceItem), GetElementName(item), CreateXPathString(wieInner.SourceItem)); errormessage = SR.GetString(SR.WsdlImportErrorMessageDetail, GetElementName(item), CreateXPathString(wie.SourceItem), dependencyMessage); } else { errormessage = SR.GetString(SR.WsdlImportErrorMessageDetail, GetElementName(item), CreateXPathString(wie.SourceItem), wie.Message); } importErrors.Add(item, wie); this.Errors.Add(new MetadataConversionError(errormessage, false)); } static Exception CreateBeforeImportExtensionException(IWsdlImportExtension importer, Exception e) { string errorMessage = SR.GetString(SR.WsdlExtensionBeforeImportError, importer.GetType().AssemblyQualifiedName, e.Message); return new InvalidOperationException(errorMessage, e); } Exception CreateAlreadyFaultedException(WsdlNS.NamedItem item) { WsdlImportException innerException = importErrors[item]; string warningMsg = SR.GetString(SR.WsdlItemAlreadyFaulted, GetElementName(item)); return new AlreadyFaultedException(warningMsg, innerException); } static Exception CreateExtensionException(IWsdlImportExtension importer, Exception e) { string errorMessage = SR.GetString(SR.WsdlExtensionImportError, importer.GetType().FullName, e.Message); //consider Microsoft, allow internal exceptions to throw WsdlImportException and handle it in some special way? return new InvalidOperationException(errorMessage, e); } class AlreadyFaultedException : InvalidOperationException { internal AlreadyFaultedException(string message, WsdlImportException innerException) : base(message, innerException) { } } class WsdlImportException : Exception { WsdlNS.NamedItem sourceItem; readonly string xPath = null; WsdlImportException(WsdlNS.NamedItem item, Exception innerException) : base(string.Empty, innerException) { this.xPath = CreateXPathString(item); this.sourceItem = item; } internal static WsdlImportException Create(WsdlNS.NamedItem item, Exception innerException) { WsdlImportException wie = innerException as WsdlImportException; if (wie != null && wie.IsChildNodeOf(item)) { wie.sourceItem = item; return wie; } else { AlreadyFaultedException afe = innerException as AlreadyFaultedException; if (afe != null) return new WsdlImportException(item, afe.InnerException); else return new WsdlImportException(item, innerException); } } internal bool IsChildNodeOf(WsdlNS.NamedItem item) { return this.XPath.StartsWith(CreateXPathString(item), StringComparison.Ordinal); } internal string XPath { get { return xPath; } } internal WsdlNS.NamedItem SourceItem { get { return sourceItem; } } public override string Message { get { Exception messageException = this.InnerException; while (messageException is WsdlImportException) messageException = messageException.InnerException; if (messageException == null) return string.Empty; return messageException.Message; } } } internal class WsdlPolicyReader { WsdlImporter importer; WsdlPolicyDictionary policyDictionary; static readonly string[] EmptyStringArray = new string[0]; internal WsdlPolicyReader(WsdlImporter importer) { this.importer = importer; this.policyDictionary = new WsdlPolicyDictionary(importer); importer.PolicyWarningOccured += this.LogPolicyNormalizationWarning; } IEnumerable> GetPolicyAlternatives(WsdlNS.NamedItem item, WsdlNS.ServiceDescription wsdl) { Collection policyElements = new Collection(); foreach (XmlElement element in GetReferencedPolicy(item, wsdl)) { policyElements.Add(element); } foreach (XmlElement element in GetEmbeddedPolicy(item)) { policyElements.Add(element); if (!policyDictionary.PolicySourceTable.ContainsKey(element)) policyDictionary.PolicySourceTable.Add(element, wsdl); } return importer.NormalizePolicy(policyElements); } void LogPolicyNormalizationWarning(XmlElement contextAssertion, string warningMessage) { string xPath = null; if (contextAssertion != null) xPath = this.policyDictionary.CreateIdXPath(contextAssertion); StringBuilder warningMsg = new StringBuilder(); warningMsg.AppendLine(warningMessage); if (!string.IsNullOrEmpty(xPath)) { warningMsg.AppendLine(SR.GetString(SR.XPathPointer, xPath)); } else { // // We were given a context assertion that we couldn't get an XPath for // warningMsg.AppendLine(SR.GetString(SR.XPathPointer, SR.GetString(SR.XPathUnavailable))); } importer.LogImportWarning(warningMsg.ToString()); } internal static bool ContainsPolicy(WsdlNS.Binding wsdlBinding) { if (HasPolicyAttached(wsdlBinding)) return true; foreach (WsdlNS.OperationBinding wsdlOperationBinding in wsdlBinding.Operations) { if (HasPolicyAttached(wsdlOperationBinding)) { return true; } if (wsdlOperationBinding.Input != null && HasPolicyAttached(wsdlOperationBinding.Input)) { return true; } if (wsdlOperationBinding.Output != null && HasPolicyAttached(wsdlOperationBinding.Output)) { return true; } foreach (WsdlNS.FaultBinding faultBinding in wsdlOperationBinding.Faults) { if (HasPolicyAttached(faultBinding)) { return true; } } } return false; } internal static bool HasPolicy(WsdlNS.Port wsdlPort) { return HasPolicyAttached(wsdlPort); } internal static IEnumerable GetEmbeddedPolicy(WsdlNS.NamedItem item) { List embeddedPolicies = new List(); embeddedPolicies.AddRange(item.Extensions.FindAll(MetadataStrings.WSPolicy.Elements.Policy, MetadataStrings.WSPolicy.NamespaceUri)); embeddedPolicies.AddRange(item.Extensions.FindAll(MetadataStrings.WSPolicy.Elements.Policy, MetadataStrings.WSPolicy.NamespaceUri15)); return embeddedPolicies; } IEnumerable GetReferencedPolicy(WsdlNS.NamedItem item, WsdlNS.ServiceDescription wsdl) { string xPath = CreateXPathString(item); foreach (string policyRef in GetPolicyReferenceUris(item, xPath)) { XmlElement policy = policyDictionary.ResolvePolicyReference(policyRef, wsdl); if (policy == null) { StringBuilder warningMsg = new StringBuilder(); warningMsg.AppendLine(SR.GetString(SR.UnableToFindPolicyWithId, policyRef)); warningMsg.AppendLine(SR.GetString(SR.XPathPointer, xPath)); importer.LogImportWarning(warningMsg.ToString()); continue; } yield return policy; } } IEnumerable GetPolicyReferenceUris(WsdlNS.NamedItem item, string xPath) { // // get policy from wsp:PolicyUris attribute // foreach (string policyUri in ReadPolicyUrisAttribute(item)) yield return policyUri; // // get policy from Elements // foreach (string policyUri in ReadPolicyReferenceElements(item, xPath)) yield return policyUri; } IEnumerable ReadPolicyReferenceElements(WsdlNS.NamedItem item, string xPath) { List policyReferences = new List(); policyReferences.AddRange(item.Extensions.FindAll(MetadataStrings.WSPolicy.Elements.PolicyReference, MetadataStrings.WSPolicy.NamespaceUri)); policyReferences.AddRange(item.Extensions.FindAll(MetadataStrings.WSPolicy.Elements.PolicyReference, MetadataStrings.WSPolicy.NamespaceUri15)); foreach (XmlElement element in policyReferences) { string idRef = element.GetAttribute(MetadataStrings.WSPolicy.Attributes.URI); if (idRef == null) { string warningMsg = SR.GetString(SR.PolicyReferenceMissingURI, MetadataStrings.WSPolicy.Attributes.URI); importer.LogImportWarning(warningMsg); } else if (idRef == string.Empty) { string warningMsg = SR.GetString(SR.PolicyReferenceInvalidId); importer.LogImportWarning(warningMsg); continue; } else { yield return idRef; } } } static string[] ReadPolicyUrisAttribute(WsdlNS.NamedItem item) { XmlAttribute[] attributes = item.ExtensibleAttributes; if (attributes != null && attributes.Length > 0) { foreach (XmlAttribute attribute in attributes) { if (PolicyHelper.IsPolicyURIs(attribute)) { return attribute.Value.Split((char[])null, StringSplitOptions.RemoveEmptyEntries); } } } return EmptyStringArray; } static bool HasPolicyAttached(WsdlNS.NamedItem item) { XmlAttribute[] attributes = item.ExtensibleAttributes; if (attributes != null && Array.Exists(attributes, PolicyHelper.IsPolicyURIs)) { return true; } if (item.Extensions.Find(MetadataStrings.WSPolicy.Elements.PolicyReference, MetadataStrings.WSPolicy.NamespaceUri) != null || item.Extensions.Find(MetadataStrings.WSPolicy.Elements.PolicyReference, MetadataStrings.WSPolicy.NamespaceUri15) != null) { return true; } if (item.Extensions.Find(MetadataStrings.WSPolicy.Elements.Policy, MetadataStrings.WSPolicy.NamespaceUri) != null || item.Extensions.Find(MetadataStrings.WSPolicy.Elements.Policy, MetadataStrings.WSPolicy.NamespaceUri15) != null) { return true; } return false; } internal PolicyAlternatives GetPolicyAlternatives(WsdlEndpointConversionContext endpointContext) { PolicyAlternatives policyAlternatives = new PolicyAlternatives(); // // Create EndpointAlternatives either from wsd:binding or from CrossProduct of wsd:binding and wsdl:port policy // WsdlNS.ServiceDescription bindingWsdl = endpointContext.WsdlBinding.ServiceDescription; IEnumerable> wsdlBindingAlternatives = this.GetPolicyAlternatives(endpointContext.WsdlBinding, bindingWsdl); if (endpointContext.WsdlPort != null) { IEnumerable> wsdlPortAlternatives = this.GetPolicyAlternatives(endpointContext.WsdlPort, endpointContext.WsdlPort.Service.ServiceDescription); policyAlternatives.EndpointAlternatives = PolicyHelper.CrossProduct(wsdlBindingAlternatives, wsdlPortAlternatives, new YieldLimiter(this.importer.Quotas.MaxYields, this.importer)); } else { policyAlternatives.EndpointAlternatives = wsdlBindingAlternatives; } // // Create operation and message policy // policyAlternatives.OperationBindingAlternatives = new Dictionary>>(endpointContext.Endpoint.Contract.Operations.Count); policyAlternatives.MessageBindingAlternatives = new Dictionary>>(); policyAlternatives.FaultBindingAlternatives = new Dictionary>>(); foreach (OperationDescription operation in endpointContext.Endpoint.Contract.Operations) { // Skip operations that have Action/ReplyAction = "*" if (!WsdlExporter.OperationIsExportable(operation)) { continue; } WsdlNS.OperationBinding wsdlOperationBinding = endpointContext.GetOperationBinding(operation); try { IEnumerable> operationAlternatives = this.GetPolicyAlternatives(wsdlOperationBinding, bindingWsdl); policyAlternatives.OperationBindingAlternatives.Add(operation, operationAlternatives); foreach (MessageDescription message in operation.Messages) { WsdlNS.MessageBinding wsdlMessageBinding = endpointContext.GetMessageBinding(message); CreateMessageBindingAlternatives(policyAlternatives, bindingWsdl, message, wsdlMessageBinding); } foreach (FaultDescription fault in operation.Faults) { WsdlNS.FaultBinding wsdlFaultBinding = endpointContext.GetFaultBinding(fault); CreateFaultBindingAlternatives(policyAlternatives, bindingWsdl, fault, wsdlFaultBinding); } } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Fx.IsFatal(e)) throw; throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(WsdlImportException.Create(wsdlOperationBinding, e)); } } return policyAlternatives; } void CreateMessageBindingAlternatives(PolicyAlternatives policyAlternatives, WsdlNS.ServiceDescription bindingWsdl, MessageDescription message, WsdlNS.MessageBinding wsdlMessageBinding) { try { IEnumerable> messageAlternatives = this.GetPolicyAlternatives(wsdlMessageBinding, bindingWsdl); policyAlternatives.MessageBindingAlternatives.Add(message, messageAlternatives); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Fx.IsFatal(e)) throw; throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(WsdlImportException.Create(wsdlMessageBinding, e)); } } void CreateFaultBindingAlternatives(PolicyAlternatives policyAlternatives, WsdlNS.ServiceDescription bindingWsdl, FaultDescription fault, WsdlNS.FaultBinding wsdlFaultBinding) { try { IEnumerable> faultAlternatives = this.GetPolicyAlternatives(wsdlFaultBinding, bindingWsdl); policyAlternatives.FaultBindingAlternatives.Add(fault, faultAlternatives); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Fx.IsFatal(e)) throw; throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(WsdlImportException.Create(wsdlFaultBinding, e)); } } internal XmlElement ResolvePolicyReference(string policyReference, XmlElement contextPolicyAssertion) { return this.policyDictionary.ResolvePolicyReference(policyReference, contextPolicyAssertion); } class WsdlPolicyDictionary { readonly MetadataImporter importer; readonly Dictionary> embeddedPolicyDictionary = new Dictionary>(); readonly Dictionary externalPolicyDictionary = new Dictionary(); readonly Dictionary policySourceTable = new Dictionary(); internal Dictionary PolicySourceTable { get { return policySourceTable; } } internal WsdlPolicyDictionary(WsdlImporter importer) { this.importer = importer; // // Embedded Policy documents // foreach (WsdlNS.ServiceDescription wsdl in importer.wsdlDocuments) { foreach (XmlElement element in WsdlPolicyReader.GetEmbeddedPolicy(wsdl)) { AddEmbeddedPolicy(importer, wsdl, element); } } // // External Policy documents // foreach (KeyValuePair policyDocument in importer.policyDocuments) { AddExternalPolicy(importer, policyDocument); } } void AddEmbeddedPolicy(WsdlImporter importer, WsdlNS.ServiceDescription wsdl, XmlElement element) { string key = GetFragmentIdentifier(element); if (String.IsNullOrEmpty(key)) { string xPath = CreateXPathString(wsdl); string warningMsg = SR.GetString(SR.PolicyInWsdlMustHaveFragmentId, xPath); importer.LogImportWarning(warningMsg); return; } Dictionary wsdlPolicyDictionary; if (!this.embeddedPolicyDictionary.TryGetValue(wsdl, out wsdlPolicyDictionary)) { wsdlPolicyDictionary = new Dictionary(); this.embeddedPolicyDictionary.Add(wsdl, wsdlPolicyDictionary); } else if (wsdlPolicyDictionary.ContainsKey(key)) { string xPath = CreateIdXPath(wsdl, element, key); string warningMsg = SR.GetString(SR.DuplicatePolicyInWsdlSkipped, xPath); importer.LogImportWarning(warningMsg); return; } wsdlPolicyDictionary.Add(key, element); policySourceTable.Add(element, wsdl); } void AddExternalPolicy(WsdlImporter importer, KeyValuePair policyDocument) { if (policyDocument.Value.NamespaceURI != MetadataStrings.WSPolicy.NamespaceUri && policyDocument.Value.NamespaceURI != MetadataStrings.WSPolicy.NamespaceUri15) { string warningMsg = SR.GetString(SR.UnrecognizedPolicyDocumentNamespace, policyDocument.Value.NamespaceURI); importer.LogImportWarning(warningMsg); return; } if (PolicyHelper.GetNodeType(policyDocument.Value) != PolicyHelper.NodeType.Policy) { string warningMsg = SR.GetString(SR.UnsupportedPolicyDocumentRoot, policyDocument.Value.Name); importer.LogImportWarning(warningMsg); return; } string key = CreateKeyFromPolicy(policyDocument.Key, policyDocument.Value); if (externalPolicyDictionary.ContainsKey(key)) { string warningMsg = SR.GetString(SR.DuplicatePolicyDocumentSkipped, key); importer.LogImportWarning(warningMsg); return; } this.externalPolicyDictionary.Add(key, policyDocument.Value); } internal XmlElement ResolvePolicyReference(string policyReference, XmlElement contextPolicyAssertion) { XmlElement policy; if (policyReference[0] != '#') { externalPolicyDictionary.TryGetValue(policyReference, out policy); return policy; } if (contextPolicyAssertion == null) { return null; } WsdlNS.ServiceDescription sourceWsdl; if (!policySourceTable.TryGetValue(contextPolicyAssertion, out sourceWsdl)) { return null; } return ResolvePolicyReference(policyReference, sourceWsdl); } internal XmlElement ResolvePolicyReference(string policyReference, WsdlNS.ServiceDescription wsdlDocument) { XmlElement policy; if (policyReference[0] != '#') { externalPolicyDictionary.TryGetValue(policyReference, out policy); return policy; } Dictionary wsdlPolicyDictionary; if (!this.embeddedPolicyDictionary.TryGetValue(wsdlDocument, out wsdlPolicyDictionary)) { return null; } wsdlPolicyDictionary.TryGetValue(policyReference, out policy); return policy; } static string CreateKeyFromPolicy(string identifier, XmlElement policyElement) { string policyId = GetFragmentIdentifier(policyElement); string policyUri = string.Format(CultureInfo.InvariantCulture, "{0}{1}", identifier, policyId); return policyUri; } static string GetFragmentIdentifier(XmlElement element) { return PolicyHelper.GetFragmentIdentifier(element); } static readonly string wspPolicy = string.Format(CultureInfo.InvariantCulture, "{0}:{1}", MetadataStrings.WSPolicy.Prefix, MetadataStrings.WSPolicy.Elements.Policy); static readonly string xmlId = string.Format(CultureInfo.InvariantCulture, "{0}:{1}", MetadataStrings.Xml.Prefix, MetadataStrings.Xml.Attributes.Id); static readonly string wsuId = string.Format(CultureInfo.InvariantCulture, "{0}:{1}", MetadataStrings.Wsu.Prefix, MetadataStrings.Wsu.Attributes.Id); internal string CreateIdXPath(XmlElement policyAssertion) { WsdlNS.ServiceDescription sourceWsdl; if (!policySourceTable.TryGetValue(policyAssertion, out sourceWsdl)) { return null; } string key = GetFragmentIdentifier(policyAssertion); if (string.IsNullOrEmpty(key)) { return null; } return CreateIdXPath(sourceWsdl, policyAssertion, key); } internal static string CreateIdXPath(WsdlNS.ServiceDescription wsdl, XmlElement element, string key) { string xPath = CreateXPathString(wsdl); string idAttrib; if (element.HasAttribute(MetadataStrings.Wsu.Attributes.Id, MetadataStrings.Wsu.NamespaceUri)) { idAttrib = wsuId; } else if (element.HasAttribute(MetadataStrings.Xml.Attributes.Id, MetadataStrings.Xml.NamespaceUri)) { idAttrib = xmlId; } else { Fx.Assert("CreateIdXPath always called with a valid key"); return null; } return string.Format(CultureInfo.InvariantCulture, "{0}/{1}/[@{2}='{3}']", xPath, wspPolicy, idAttrib, key); } } } enum ErrorBehavior { RethrowExceptions, DoNotThrowExceptions, } enum WsdlPortTypeImportOptions { ReuseExistingContracts, IgnoreExistingContracts, } } }