Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / xsp / System / Web / Extensions / Compilation / WCFModel / VSWCFServiceContractGenerator.cs / 2 / VSWCFServiceContractGenerator.cs
//------------------------------------------------------------------------------ //// Copyright (C) Microsoft Corporation. All Rights Reserved. // //----------------------------------------------------------------------------- using System; using System.CodeDom; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Configuration; using System.Globalization; using System.Reflection; using System.Runtime.Serialization; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Configuration; using System.ServiceModel.Description; using System.Web.Services.Description; using System.Xml; using System.Xml.Schema; using System.Security.Permissions; #if WEB_EXTENSIONS_CODE using System.Web.Resources; #else using Microsoft.VSDesigner.Resources.Microsoft.VSDesigner; #endif /// /// The VSWCFServiceContractGenerator takes a SvcMap file and it's associated metadata, /// imports the metadata using a WsdlImporter and System.ServiceModel.ServiceContractGenerator /// that are configured according to the options set in the SvcMap file /// using Debug = System.Diagnostics.Debug; #if WEB_EXTENSIONS_CODE namespace System.Web.Compilation.WCFModel #else namespace Microsoft.VSDesigner.WCFModel #endif { ////// Proxy and configuration generator /// #if WEB_EXTENSIONS_CODE [PermissionSet(SecurityAction.LinkDemand, Name="FullTrust"), PermissionSet(SecurityAction.InheritanceDemand, Name="FullTrust")] internal class VSWCFServiceContractGenerator #else // We only check for CLS compliant for the public version of this class since the // compiler will complain about CLS compliance not being checked for non-public classes [CLSCompliant(true), PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust"), PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")] public class VSWCFServiceContractGenerator #endif { #region Private backing fields private const string VB_LANGUAGE_NAME = "vb"; ////// Collection to hold all bindings generated by this generator /// private IEnumerablebindingCollection; /// /// Collection to hold all contracts generated by this generator /// private IEnumerablecontractCollection; /// /// Collection to hold all endpoints generated by this generator /// private ListserviceEndpointList; /// /// Map from service endpoint to the channel endpoint that was actually imported /// private DictionaryserviceEndpointToChannelEndpointElementMap; /// /// List of contract types generate by this generator /// private ListproxyGeneratedContractTypes; /// /// The target compile unit that contains the proxy and data contracts /// private CodeCompileUnit targetCompileUnit; ////// Configuration object that we inserterd bindings and endpoints from the /// current service into. May be Null/Nothing. /// private System.Configuration.Configuration targetConfiguration; ////// Errors encountered while generating the proxy /// private IEnumerableproxyGenerationErrors; /// /// Errors encountered while importing the metadata.. /// private IListimportErrors; /// /// Helper property that is added to Out parameters for VB /// private static CodeAttributeDeclaration outAttribute; ////// version number for 3.5 framework /// private const int FRAMEWORK_VERSION_35 = 0x30005; ////// list of types which are new in the 3.5 framework. /// private static Type[] unsupportedTypesInFramework30 = new Type[] { typeof(DateTimeOffset), }; #endregion #region Public read-only properties ////// The collection of bindings generated by this generator /// ////// /// public IEnumerableBindingCollection { get { System.Diagnostics.Debug.Assert(bindingCollection != null); return bindingCollection; } } /// /// The collection of generated contract types /// public IEnumerableProxyGeneratedContractTypes { get { System.Diagnostics.Debug.Assert(proxyGeneratedContractTypes != null); return proxyGeneratedContractTypes; } } /// /// The collection of errors encountered while generating the /// proxy. For errors related to the metadata import, use the /// ImportErrors property /// public IEnumerableProxyGenerationErrors { get { System.Diagnostics.Debug.Assert(proxyGenerationErrors != null); return proxyGenerationErrors; } } /// /// The collection of errors encountered while importing metadata. /// For errors related to the proxy and config generation, use the /// ProxyGenerationErrors property /// public IEnumerableImportErrors { get { System.Diagnostics.Debug.Assert(importErrors != null); return importErrors; } } /// /// The collection of contracts imported by this generator /// ////// public IEnumerable ContractCollection { get { System.Diagnostics.Debug.Assert(contractCollection != null); return contractCollection; } } /// /// Collection of Endpoints in the service model generated by /// this generator /// ////// public IEnumerable EndpointCollection { get { System.Diagnostics.Debug.Assert(serviceEndpointList != null); return serviceEndpointList; } } /// /// Map from service endpoints to its corresponding channel endpoint configuration /// element /// public DictionaryEndpointMap { get { System.Diagnostics.Debug.Assert(serviceEndpointToChannelEndpointElementMap != null); return serviceEndpointToChannelEndpointElementMap; } } /// /// The configuratin into which we inject the bindings and endpoints. May be null/Nothing /// if no target configuration was provided. /// public System.Configuration.Configuration TargetConfiguration { get { // Note: it is valid for this to be NULL. Caller beware! return targetConfiguration; } } ////// CodeCompileUnit containing the generated data contracts, service contracts /// and WCF client. /// public CodeCompileUnit TargetCompileUnit { get { System.Diagnostics.Debug.Assert(targetCompileUnit != null); return targetCompileUnit; } } #endregion ////// Cached instance of an Out attribute that we use to patch up /// the codegen for VB projects (the VB code generates out parameters /// as ByRef) /// private static CodeAttributeDeclaration OutAttribute { get { if (outAttribute == null) { outAttribute = new CodeAttributeDeclaration(typeof(System.Runtime.InteropServices.OutAttribute).FullName); } return outAttribute; } } ////// protected constructor to block creating instance directly. /// /// /// /// May be null /// /// /// /// /// /// protected VSWCFServiceContractGenerator( ListimportErrors, CodeCompileUnit targetCompileUnit, System.Configuration.Configuration targetConfiguration, IEnumerable bindingCollection, IEnumerable contractCollection, List serviceEndpointList, Dictionary serviceEndpointToChannelEndpointElementMap, List proxyGeneratedContractTypes, IEnumerable proxyGenerationErrors) { if (importErrors == null) throw new ArgumentNullException("importErrors"); if (targetCompileUnit == null) throw new ArgumentNullException("targetCompileUnit"); // Please note - target configuration may be NULL if (bindingCollection == null) throw new ArgumentNullException("bindingCollection"); if (contractCollection == null) throw new ArgumentNullException("contractCollection"); if (serviceEndpointList == null) throw new ArgumentNullException("serviceEndpointList"); if (serviceEndpointToChannelEndpointElementMap == null) throw new ArgumentNullException("serviceEndpointToChannelEndpointElementMap"); if (proxyGeneratedContractTypes == null) throw new ArgumentNullException("proxyGeneratedContractTypes"); if (proxyGenerationErrors == null) throw new ArgumentNullException("proxyGenerationErrors"); this.importErrors = importErrors; this.targetCompileUnit = targetCompileUnit; this.targetConfiguration = targetConfiguration; this.bindingCollection = bindingCollection; this.contractCollection = contractCollection; this.serviceEndpointList = serviceEndpointList; this.serviceEndpointToChannelEndpointElementMap = serviceEndpointToChannelEndpointElementMap; this.proxyGeneratedContractTypes = proxyGeneratedContractTypes; this.proxyGenerationErrors = proxyGenerationErrors; } /// /// Factory method: generate code and return the resulting VSWCFServiceContractGenerator. /// /// /// The SvcMapFile that lists the metadata and generation options for the service reference. /// /// /// Configuration from which we are going to pick up WSDL and policy importer extensions as well /// as custom MEX bindings for metadata download. May be Null/Nothing. /// /// /// CodeDom provider that is to be used to generate the client code. /// /// /// CLR namespace in which to generate the client code. /// /// /// The configuration into which we will put bindings/endpoints for this service /// reference. May be Null/Nothing. /// /// /// The namespace that is to be used in configuration for this service reference. /// /// /// Service provider that we'll pass on to import extensions that accept our site:ing /// mechanism /// /// /// Type loader that can be used to find reference assemblies and/or resolve shared service and /// data contract types. /// /// /// The target framework version number. The higher 16 bits contains the major version number, and low 16 bits contains minor version number. /// /// /// Schema importer extension to be used for typed datasets. /// ////// A VSWCFServiceContractGenerator instance that contains the result of the generation. To get /// hold of the generated information, you can query it's properties. /// public static VSWCFServiceContractGenerator GenerateCodeAndConfiguration(SvcMapFile svcMapFile, System.Configuration.Configuration toolConfiguration, System.CodeDom.Compiler.CodeDomProvider codeDomProvider, string proxyNamespace, System.Configuration.Configuration targetConfiguration, string configurationNamespace, IServiceProvider serviceProviderForImportExtensions, IContractGeneratorReferenceTypeLoader typeLoader, int targetFrameworkVersion, System.Type typedDataSetSchemaImporterExtension) { if (svcMapFile == null) throw new ArgumentNullException("svcMapFile"); if (codeDomProvider == null) throw new ArgumentNullException("codeDomProvider"); if (typedDataSetSchemaImporterExtension == null) throw new ArgumentNullException("typedDataSetSchemaImporterExtension"); ListimportErrors = new List (); List proxyGenerationErrors = new List (); CodeCompileUnit targetCompileUnit = new CodeCompileUnit(); WsdlImporter wsdlImporter = CreateWsdlImporter(svcMapFile, toolConfiguration, targetCompileUnit, codeDomProvider, proxyNamespace, serviceProviderForImportExtensions, typeLoader, targetFrameworkVersion, importErrors, typedDataSetSchemaImporterExtension); ServiceContractGenerator contractGenerator = CreateContractGenerator(svcMapFile.ClientOptions, wsdlImporter, targetCompileUnit, proxyNamespace, targetConfiguration, typeLoader, targetFrameworkVersion, importErrors); try { List serviceEndpointList = new List (); IEnumerable bindingCollection; IEnumerable contractCollection; ImportWCFModel(wsdlImporter, targetCompileUnit, importErrors, out serviceEndpointList, out bindingCollection, out contractCollection); Dictionary serviceEndpointToChannelEndpointElementMap; List proxyGeneratedContractTypes; GenerateProxy(contractGenerator, targetCompileUnit, proxyNamespace, configurationNamespace, contractCollection, bindingCollection, serviceEndpointList, proxyGenerationErrors, out serviceEndpointToChannelEndpointElementMap, out proxyGeneratedContractTypes); if (IsVBCodeDomProvider(codeDomProvider)) { PatchOutParametersInVB(targetCompileUnit); } return new VSWCFServiceContractGenerator(importErrors, targetCompileUnit, targetConfiguration, bindingCollection, contractCollection, serviceEndpointList, serviceEndpointToChannelEndpointElementMap, proxyGeneratedContractTypes, proxyGenerationErrors); } catch (Exception ex) { // fatal error... (workaround for bug #135242) // We want to convert fatal error exception to a normal code generator error message, // so the user could find information from pervious errors to find KB topic. proxyGenerationErrors.Add(new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, ex, false)); return new VSWCFServiceContractGenerator(importErrors, new CodeCompileUnit(), targetConfiguration, new List (), new List (), new List (), new Dictionary (), new List (), proxyGenerationErrors); } } /// /// Instantiate and configure a ServiceContractGenerator to be used for code and config /// generation. /// /// /// Options set in the SvcMap file to control the code/config generation. /// /// /// The WsdlImporter that is to be used to import the metadata for this service reference. /// /// /// Compile unit into which we will generate the client code /// /// /// The CLR namespace into which we will generate the client code. /// /// /// Optional configuration into which we will generate the endpoints/bindings corresponding /// to this service reference. May be Null/Nothing, in which case we will not generate config. /// /// /// Type loader that can be used to find reference assemblies and/or resolve shared service and /// data contract types. /// /// /// The target framework version number. The higher 16 bits contains the major version number, and low 16 bits contains minor version number. /// /// /// The list into which we will add any errors while importing the metadata. /// ///protected static ServiceContractGenerator CreateContractGenerator(ClientOptions proxyOptions, WsdlImporter wsdlImporter, CodeCompileUnit targetCompileUnit, string proxyNamespace, System.Configuration.Configuration targetConfiguration, IContractGeneratorReferenceTypeLoader typeLoader, int targetFrameworkVersion, IList importErrors) { ServiceContractGenerator contractGenerator = new ServiceContractGenerator(targetCompileUnit, targetConfiguration); // We want to generate all types into the proxy namespace CLR namespace. We indicate // this by adding a namespace mapping from all XML namespaces ("*") to the namespace // the caller told us to generate the client code in. contractGenerator.NamespaceMappings.Add("*", proxyNamespace); if (proxyOptions.GenerateInternalTypes) { contractGenerator.Options |= ServiceContractGenerationOptions.InternalTypes; } else { contractGenerator.Options &= ~ServiceContractGenerationOptions.InternalTypes; } if (proxyOptions.GenerateAsynchronousMethods) { contractGenerator.Options |= ServiceContractGenerationOptions.AsynchronousMethods; if (targetFrameworkVersion >= FRAMEWORK_VERSION_35) { contractGenerator.Options |= ServiceContractGenerationOptions.EventBasedAsynchronousMethods; } } else { contractGenerator.Options &= ~ServiceContractGenerationOptions.AsynchronousMethods; } if (proxyOptions.GenerateMessageContracts) { contractGenerator.Options |= ServiceContractGenerationOptions.TypedMessages; } else { contractGenerator.Options &= ~ServiceContractGenerationOptions.TypedMessages; } // If we have a type loader, we tell the contract generator and wsdl importer about // all shared types and assemblies that we've specified in the proxy options... if (typeLoader != null) { foreach (ContractMapping mapping in proxyOptions.ServiceContractMappingList) { try { Type sharedType = typeLoader.LoadType(mapping.TypeName); // verify that the type is shareable - if not, we generate an error... if (!IsTypeShareable(sharedType)) { importErrors.Add( new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, new FormatException(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_SharedTypeMustBePublic, mapping.TypeName))) ); continue; } // Get a contract description corresponding to the type we wanted to share ContractDescription contract = ContractDescription.GetContract(sharedType); if (!String.Equals(mapping.Name, contract.Name, StringComparison.Ordinal) || !String.Equals(mapping.TargetNamespace, contract.Namespace, StringComparison.Ordinal)) { // mismatch importErrors.Add( new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, new FormatException(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_ServiceContractMappingMissMatch, mapping.TypeName, contract.Namespace, contract.Name, mapping.TargetNamespace, mapping.Name))) ); } XmlQualifiedName qname = new XmlQualifiedName(contract.Name, contract.Namespace); wsdlImporter.KnownContracts.Add(qname, contract); contractGenerator.ReferencedTypes.Add(contract, sharedType); } catch (Exception ex) { importErrors.Add(new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, ex)); } } } foreach (NamespaceMapping namespaceMapping in proxyOptions.NamespaceMappingList) { contractGenerator.NamespaceMappings.Add(namespaceMapping.TargetNamespace, namespaceMapping.ClrNamespace); } return contractGenerator; } /// /// Generate Proxy Code and (if available) configuration /// /// The contract generator to use /// Compile unit into which we should generate the client code /// CLR namespace into which we should generate the client code /// Namespace to use in configuration /// The contracts for which we should generate code and optionally config /// The bindings we should generate config for /// The endpoints we should generate config for /// A list of errors encountered while generating the client /// Map from service endpoint to the configuration element for the endpoint /// The generated contract types protected static void GenerateProxy(ServiceContractGenerator contractGenerator, CodeCompileUnit targetCompileUnit, string proxyNamespace, string configurationNamespace, IEnumerablecontractCollection, IEnumerable bindingCollection, List serviceEndpointList, IList proxyGenerationErrors, out Dictionary serviceEndpointToChannelEndpointElementMap, out List proxyGeneratedContractTypes) { // Parameter checking if (serviceEndpointList == null) throw new ArgumentNullException("serviceEndpointList"); if (bindingCollection == null) throw new ArgumentNullException("bindingCollection"); if (contractCollection == null) throw new ArgumentNullException("contractCollection"); if (proxyGenerationErrors == null) throw new ArgumentNullException("proxyGenerationErrors"); proxyGeneratedContractTypes = new List (); serviceEndpointToChannelEndpointElementMap = new Dictionary (); try { foreach (ContractDescription contract in contractCollection) { CodeTypeReference typeReference = contractGenerator.GenerateServiceContractType(contract); if (typeReference != null) { // keep the (targetNamespace, portType) -> CLR type map table... string baseType = typeReference.BaseType; GeneratedContractType generatedType = new GeneratedContractType(contract.Namespace, contract.Name, baseType, baseType); proxyGeneratedContractTypes.Add(generatedType); } } // We should only import the Binding & Endpoints if there is a configuration storage... if (contractGenerator.Configuration != null) { foreach (ServiceEndpoint endpoint in serviceEndpointList) { ChannelEndpointElement endpointElement = null; contractGenerator.GenerateServiceEndpoint(endpoint, out endpointElement); serviceEndpointToChannelEndpointElementMap[endpoint] = endpointElement; } foreach (System.ServiceModel.Channels.Binding bindingDescription in bindingCollection) { string bindingSectionName = null; string bindingConfigurationName = null; // Generate binding will change the state of the contractGenerator... contractGenerator.GenerateBinding(bindingDescription, out bindingSectionName, out bindingConfigurationName); } } PatchConfigurationName(proxyNamespace, configurationNamespace, proxyGeneratedContractTypes, serviceEndpointToChannelEndpointElementMap.Values, targetCompileUnit); } finally { foreach (MetadataConversionError error in contractGenerator.Errors) { proxyGenerationErrors.Add(new ProxyGenerationError(error)); } } } /// /// Create appropriate XmlSerializerImportOptions for the generator /// /// Options for the code/config generation /// Compile unit we are going to generate the client code in /// CodeDom provider for the language we are using /// CLR namespace we'll put the client code in ///protected static XmlSerializerImportOptions CreateXmlSerializerImportOptions( ClientOptions proxyOptions, CodeCompileUnit targetCompileUnit, System.CodeDom.Compiler.CodeDomProvider codeDomProvider, string proxyNamespace, System.Type typedDataSetSchemaImporterExtension) { System.ServiceModel.Channels.XmlSerializerImportOptions xmlSerializerOptions = new XmlSerializerImportOptions(targetCompileUnit); System.Web.Services.Description.WebReferenceOptions webReferenceOptions = new System.Web.Services.Description.WebReferenceOptions(); webReferenceOptions.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateProperties | System.Xml.Serialization.CodeGenerationOptions.GenerateOrder; if (proxyOptions.EnableDataBinding) { webReferenceOptions.CodeGenerationOptions |= System.Xml.Serialization.CodeGenerationOptions.EnableDataBinding; } webReferenceOptions.SchemaImporterExtensions.Add(typedDataSetSchemaImporterExtension.AssemblyQualifiedName); webReferenceOptions.SchemaImporterExtensions.Add(typeof(System.Data.DataSetSchemaImporterExtension).AssemblyQualifiedName); /* */ xmlSerializerOptions.WebReferenceOptions = webReferenceOptions; xmlSerializerOptions.CodeProvider = codeDomProvider; xmlSerializerOptions.ClrNamespace = proxyNamespace; return xmlSerializerOptions; } /// /// Create an appropriate XsdDataContractImporter for the generator /// /// Code/config generation options to use /// CodeCompileUnit into which we will generate the client code /// CodeDomProvider for the language we will use to generate the client /// CLR namespace in which the client code will be generated /// Service used to resolve type/assembly names (strings) to actual Types and Assemblies /// Targetted Framework version number /// List of errors encountered. New errors will be added to this list ///protected static XsdDataContractImporter CreateDataContractImporter( ClientOptions proxyOptions, CodeCompileUnit targetCompileUnit, System.CodeDom.Compiler.CodeDomProvider codeDomProvider, string proxyNamespace, IContractGeneratorReferenceTypeLoader typeLoader, int targetFrameworkVersion, IList importErrors) { System.Runtime.Serialization.XsdDataContractImporter xsdDataContractImporter = new System.Runtime.Serialization.XsdDataContractImporter(targetCompileUnit); System.Runtime.Serialization.ImportOptions options = new System.Runtime.Serialization.ImportOptions(); options.CodeProvider = codeDomProvider; // We specify that we want to generate all types from all XML namespaces into // our proxy namespace. By default, each XML namespace get's its own CLR namespace options.Namespaces.Add("*", proxyNamespace); options.GenerateInternal = proxyOptions.GenerateInternalTypes; options.GenerateSerializable = proxyOptions.GenerateSerializableTypes; options.EnableDataBinding = proxyOptions.EnableDataBinding; options.ImportXmlType = proxyOptions.ImportXmlTypes; if (typeLoader != null) { IEnumerable referencedTypes = LoadSharedDataContractTypes(proxyOptions, typeLoader, targetFrameworkVersion, importErrors); if (referencedTypes != null) { foreach (Type sharedType in referencedTypes) { options.ReferencedTypes.Add(sharedType); } } IEnumerable referencedCollectionTypes = LoadSharedCollectionTypes(proxyOptions, typeLoader, importErrors); if (referencedCollectionTypes != null) { foreach (Type collectionType in referencedCollectionTypes) { options.ReferencedCollectionTypes.Add(collectionType); } } } foreach (NamespaceMapping namespaceMapping in proxyOptions.NamespaceMappingList) { options.Namespaces.Add(namespaceMapping.TargetNamespace, namespaceMapping.ClrNamespace); } xsdDataContractImporter.Options = options; return xsdDataContractImporter; } /// /// Load DataContract types which could be used in the code generator (shared types) /// /// Options controlling the generation /// Type loader to resolve referenced assemblies and types /// Targetted Framework version number /// Errors encountered while loading the shared data contracts ////// A list of CLR types from referenced assemblies and/or specific types that we want to share /// ///protected static IEnumerable LoadSharedDataContractTypes( ClientOptions proxyOptions, IContractGeneratorReferenceTypeLoader typeLoader, int targetFrameworkVersion, IList importErrors) { if (typeLoader == null) throw new ArgumentNullException("typeLoader"); // the value in sharedTypeTable is why we add this type in the shared type list. // if it is only added because it is in the referenced assembly, the value will be null, otherwise it contains the entry in the type inclusion list // if the type is also in the exclusion list, we will report an error if the type is comming from the inclusion list, but no error if it comes from a referenced assembly only. Dictionary sharedTypeTable = new Dictionary (); // load all types in referencedAssemblies IEnumerable referencedAssemblies = LoadReferenedAssemblies(proxyOptions, typeLoader, importErrors); if (referencedAssemblies != null) { foreach (Assembly referencedAssembly in referencedAssemblies) { try { foreach (Type typeInAssembly in referencedAssembly.GetTypes()) { if (IsTypeShareable(typeInAssembly)) { sharedTypeTable.Add(typeInAssembly, null); } } } catch (Exception ex) { // fail to load one type in an assembly: warning message importErrors.Add( new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, ex, true)); } } } // load types in DataContractTypeList foreach (ReferencedType referencedType in proxyOptions.ReferencedDataContractTypeList) { try { Type sharedType = typeLoader.LoadType(referencedType.TypeName); // verify... if (!IsTypeShareable(sharedType)) { importErrors.Add( new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, new FormatException(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_SharedTypeMustBePublic, referencedType.TypeName))) ); continue; } sharedTypeTable[sharedType] = referencedType; } catch (Exception ex) { importErrors.Add(new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, ex)); } } // remove excluded types foreach (ReferencedType excludedType in proxyOptions.ExcludedTypeList) { try { Type sharedType = typeLoader.LoadType(excludedType.TypeName); if (sharedTypeTable.ContainsKey(sharedType)) { if (sharedTypeTable[sharedType] != null) { // error message importErrors.Add(new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, new Exception(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_DataContractExcludedAndIncluded, excludedType.TypeName)))); } sharedTypeTable.Remove(sharedType); } } catch (Exception ex) { // waring message for excludedTypes importErrors.Add(new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, ex, true)); } } // remove unsupported types foreach (Type unsupportedType in GetUnsupportedTypes(targetFrameworkVersion)) { sharedTypeTable.Remove(unsupportedType); } return sharedTypeTable.Keys; } /// /// Get list of types which are not supported in the targetted framework. /// /// Targetted Framework version number ////// private static IEnumerable GetUnsupportedTypes(int targetFrameworkVersion) { if (targetFrameworkVersion < FRAMEWORK_VERSION_35) { // NOTE: do we need load those types with typeLoader? return unsupportedTypesInFramework30; } return new Type[0]; } /// /// Ensure that the ConfigurationName attribute on service contracts and the channel endpoint elements all agree on the /// name of the service contract. /// We want to avoid having root/default namespace values persisted in config, since that would require us /// to update config whenever the default/root namespace changes, so we make sure that we exclude it /// from the ConfigurationName attribute and the channel endpoint element we generate. /// /// For VB, the root namespace is not actually present in the generated code, so we typically don't have to /// do anything (the configuration and proxy namespaces are equal) but for C#, we need to strip out the /// default namespace. /// /// /// CLR namespace into which we will generate the service in the CodeCompileUnit /// /// /// The namespace that we expect to use in configuration. /// /// /// The contracts that we have generated /// /// /// All channel endpoints we have generated /// /// /// The compile unit into which we generated the client /// private static void PatchConfigurationName( string proxyNamespace, string configNamespace, IEnumerablegeneratedContracts, IEnumerable endpoints, CodeCompileUnit targetCompileUnit ) { // Since the name has to match between configuration and the name we put in the ConfigurationName // attribute in code, we may have some patching to do - but only if the proxy namespace is not equal // to the configuration namespace... if (configNamespace != null && !configNamespace.Equals(proxyNamespace, StringComparison.Ordinal)) { string proxyNamespaceHead = MakePeriodTerminatedNamespacePrefix(proxyNamespace); string configNamespaceHead = MakePeriodTerminatedNamespacePrefix(configNamespace); // We need to fix up the configuration name for all generated contracts... foreach (GeneratedContractType contract in generatedContracts) { contract.ConfigurationName = ReplaceNamespace(proxyNamespaceHead, configNamespaceHead, contract.ConfigurationName); } // ..and we need to fix up all elements in config... foreach (ChannelEndpointElement endpoint in endpoints) { endpoint.Contract = ReplaceNamespace(proxyNamespaceHead, configNamespaceHead, endpoint.Contract); } // ...and all ConfigurationName values in service contract attributes in the generated code as well... PatchConfigurationNameInServiceContractAttribute(targetCompileUnit, proxyNamespace, configNamespace); } } /// /// If the type name begins with the namespace specified in originalNamespace, replace the namespace /// for the given type name with the namespace specified in the replacementNamespace parameter. /// /// /// Original namespace to look for. /// Must either be an empty string ("") or end with a period (".") /// /// /// Namespace to replace original namespace with /// Muse either be an empty string ("") or end with a period... /// /// Typename on which to do the replacement ////// The new type name (potentially the same as passed in) /// private static string ReplaceNamespace(string originalNamespace, string replacementNamespace, string typeName) { Debug.Assert(originalNamespace.Length == 0 || originalNamespace.EndsWith(".", StringComparison.Ordinal)); Debug.Assert(replacementNamespace.Length == 0 || replacementNamespace.EndsWith(".", StringComparison.Ordinal)); Debug.Assert(typeName != null); if (typeName.StartsWith(originalNamespace, StringComparison.Ordinal)) { // Strip out the original namespace and replace it with the new namespace return replacementNamespace + typeName.Substring(originalNamespace.Length); } else { return typeName; } } ////// Given the namespace, return either an empty string (if the given namespace was NULL or emtpy) /// or a period-terminated (".") string. /// /// ////// Either an empty string or a string that ends with a period (".") /// Can never return Null... /// private static string MakePeriodTerminatedNamespacePrefix(string ns) { if (String.IsNullOrEmpty(ns)) { return ""; } else if (!ns.EndsWith(".", StringComparison.Ordinal)) { return ns + "."; } else { return ns; } } ////// Determine if a type can be shared. /// /// In order for a type to be shareable for service references, it has to be a /// public type... /// /// ///private static bool IsTypeShareable(Type t) { if (t == null) { System.Diagnostics.Debug.Fail("Why are you asking if a NULL type is shareable?"); return false; } return t.IsPublic || t.IsNestedPublic; } /// /// Load referenced assemblies /// /// /// /// ////// private static IEnumerable LoadReferenedAssemblies(ClientOptions proxyOptions, IContractGeneratorReferenceTypeLoader typeLoader, IList importErrors) { List referencedAssemblies = new List (); if (proxyOptions.ReferenceAllAssemblies) { try { IEnumerable loadingErrors = null; IEnumerable allAssemblies = null; typeLoader.LoadAllAssemblies(out allAssemblies, out loadingErrors); if (loadingErrors != null) { // treat as warning messages foreach (Exception ex in loadingErrors) { importErrors.Add(new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, ex, true)); } } if (allAssemblies != null) { referencedAssemblies.AddRange(allAssemblies); } } catch (Exception ex) { importErrors.Add(new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, ex)); } } foreach (ReferencedAssembly referencedAssembly in proxyOptions.ReferencedAssemblyList) { try { Assembly refAssembly = typeLoader.LoadAssembly(referencedAssembly.AssemblyName); if (refAssembly != null && !referencedAssemblies.Contains(refAssembly)) { referencedAssemblies.Add(refAssembly); } } catch (Exception ex) { importErrors.Add(new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, ex)); } } return referencedAssemblies; } /// /// Load the list of types that we have specified as collection types in our client options. /// The collection types will be used to generate collections in the data contracts. /// /// Options specifying the list of collection types /// Type loader that resolves type names to actual CLR types /// Errors encountered while loading the collection types ////// protected static IEnumerable LoadSharedCollectionTypes(ClientOptions proxyOptions, IContractGeneratorReferenceTypeLoader typeLoader, IList importErrors) { List referencedCollectionTypes = new List (); foreach (ReferencedCollectionType referencedCollectionMapping in proxyOptions.CollectionMappingList) { try { Type collectionType = typeLoader.LoadType(referencedCollectionMapping.TypeName); // verify... if (!IsTypeShareable(collectionType)) { importErrors.Add( new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, new FormatException(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_SharedTypeMustBePublic, referencedCollectionMapping.TypeName))) ); continue; } referencedCollectionTypes.Add(collectionType); } catch (Exception ex) { importErrors.Add(new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, ex)); } } return referencedCollectionTypes; } /// /// Create an appropriate WsdlImporter for the generator /// /// /// /// /// /// /// /// Targetted Framework version number /// /// ///protected static WsdlImporter CreateWsdlImporter(SvcMapFile svcMapFile, System.Configuration.Configuration toolConfiguration, CodeCompileUnit targetCompileUnit, System.CodeDom.Compiler.CodeDomProvider codeDomProvider, string targetNamespace, IServiceProvider serviceProviderForImportExtensions, IContractGeneratorReferenceTypeLoader typeLoader, int targetFrameworkVersion, IList importErrors, System.Type typedDataSetSchemaImporterExtension) { List metadataSections = CollectMetadataDocuments(svcMapFile.MetadataList, importErrors); WsdlImporter importer = null; ClientOptions.ProxySerializerType serializerType = svcMapFile.ClientOptions.Serializer; if (serializerType == ClientOptions.ProxySerializerType.Auto && ContainsHttpBindings(metadataSections)) { // NOTE: HTTP Get/Post binding indicates an old web service. We use XmlSerializer to prevent generating dup classes. // Please check devdiv bug 94078 serializerType = ClientOptions.ProxySerializerType.XmlSerializer; } if (toolConfiguration != null) { ServiceModelSectionGroup serviceModelSection = ServiceModelSectionGroup.GetSectionGroup(toolConfiguration); if (serviceModelSection != null) { Collection wsdlImportExtensions = serviceModelSection.Client.Metadata.LoadWsdlImportExtensions(); Collection policyImportExtensions = serviceModelSection.Client.Metadata.LoadPolicyImportExtensions(); // If we have specified a specific serializer to use, we remove // the other serializer... switch (serializerType) { case ClientOptions.ProxySerializerType.DataContractSerializer: RemoveExtension(typeof(XmlSerializerMessageContractImporter), wsdlImportExtensions); break; case ClientOptions.ProxySerializerType.XmlSerializer: RemoveExtension(typeof(DataContractSerializerMessageContractImporter), wsdlImportExtensions); break; case ClientOptions.ProxySerializerType.Auto: break; default: System.Diagnostics.Debug.Fail("Unknown serializer"); break; } ProvideImportExtensionsWithContextInformation(svcMapFile, serviceProviderForImportExtensions, wsdlImportExtensions, policyImportExtensions); // Create Importer... importer = new WsdlImporter(new MetadataSet(metadataSections), policyImportExtensions, wsdlImportExtensions); } } if (importer == null) { importer = new WsdlImporter(new MetadataSet(metadataSections)); } // DevDiv 124333 - Always add DataContract importer (even if we are in XmlSerializerMode) to // enable importing Fault contracts... importer.State.Add(typeof(System.Runtime.Serialization.XsdDataContractImporter), CreateDataContractImporter(svcMapFile.ClientOptions, targetCompileUnit, codeDomProvider, targetNamespace, typeLoader, targetFrameworkVersion, importErrors)); if (serializerType != ClientOptions.ProxySerializerType.DataContractSerializer) { importer.State.Add(typeof(System.ServiceModel.Channels.XmlSerializerImportOptions), CreateXmlSerializerImportOptions(svcMapFile.ClientOptions, targetCompileUnit, codeDomProvider, targetNamespace, typedDataSetSchemaImporterExtension)); } // Read the UseSerializerForFaults from Reference.svcmap, create a FaultImportOptions using this information // and pass it to WSDL Importer. FaultImportOptions faultOptions = new FaultImportOptions(); faultOptions.UseMessageFormat = svcMapFile.ClientOptions.UseSerializerForFaults; importer.State.Add(typeof(System.ServiceModel.FaultImportOptions), faultOptions); // Read the WrappedOptions from Reference.svcmap, create a WrappedOptions using this information // and pass it to WSDL Importer. WrappedOptions wrappedOptions = new WrappedOptions(); wrappedOptions.WrappedFlag = svcMapFile.ClientOptions.Wrapped; importer.State.Add(typeof(System.ServiceModel.Channels.WrappedOptions), wrappedOptions); return importer; } /// /// Look through all the import extensions to see if any of them want access to /// the service reference's extension files. They tell us this by implementing /// the interface IWcfReferenceReceiveContextInformation. /// /// /// /// /// internal static void ProvideImportExtensionsWithContextInformation(SvcMapFile svcMapFile, IServiceProvider serviceProviderForImportExtensions, IEnumerablewsdlImportExtensions, IEnumerable policyImportExtensions) { // Only make this copy if we need to (not the mainline case) Dictionary extensionFileContents = null; foreach (IWsdlImportExtension wsdlImportExtension in wsdlImportExtensions) { System.Web.Compilation.IWcfReferenceReceiveContextInformation receiveContext = wsdlImportExtension as System.Web.Compilation.IWcfReferenceReceiveContextInformation; if (receiveContext != null) { if (extensionFileContents == null) { extensionFileContents = CreateDictionaryOfCopiedExtensionFiles(svcMapFile); } receiveContext.ReceiveImportContextInformation( extensionFileContents, serviceProviderForImportExtensions); } } foreach (IPolicyImportExtension policyImportExtension in policyImportExtensions) { System.Web.Compilation.IWcfReferenceReceiveContextInformation receiveContext = policyImportExtension as System.Web.Compilation.IWcfReferenceReceiveContextInformation; if (receiveContext != null) { if (extensionFileContents == null) { extensionFileContents = CreateDictionaryOfCopiedExtensionFiles(svcMapFile); } receiveContext.ReceiveImportContextInformation( extensionFileContents, serviceProviderForImportExtensions); } } } /// /// Remove specific wsdl importer extension /// /// /// The extension to remove /// /// /// The collection to remove the extension from /// ////// private static void RemoveExtension(Type extensionType, Collection wsdlImportExtensions) { Debug.Assert(wsdlImportExtensions != null); for (int i = 0; i < wsdlImportExtensions.Count; i++) { if (wsdlImportExtensions[i].GetType() == extensionType) wsdlImportExtensions.RemoveAt(i); } } /// /// Creates a dictionary containing a copy of the contents of all of the extension files /// ///private static Dictionary CreateDictionaryOfCopiedExtensionFiles(SvcMapFile svcMapFile) { Dictionary extensionFileContents = new Dictionary (); foreach (ExtensionFile extensionFile in svcMapFile.Extensions) { // If the extension file was not successfully loaded, do not include it in the // collection. Users are more likely to expect that the extension file won't // be in the collection on an error than they are to assume they have to check // if the byte array we return is null or not. if (extensionFile.ContentBuffer != null && extensionFile.IsBufferValid) { extensionFileContents.Add(extensionFile.Name, (byte[])extensionFile.ContentBuffer.Clone()); } } return extensionFileContents; } /// /// Merge metadata files to prepare code generation /// ///metadata collection ///protected static List CollectMetadataDocuments(IEnumerable metadataList, IList importErrors) { List metadataCollection = new List (); foreach (MetadataFile metadataItem in metadataList) { if (!metadataItem.Ignore) { try { MetadataSection metadataSection = metadataItem.CreateMetadataSection(); if (metadataSection != null) { metadataCollection.Add(metadataSection); } } catch (Exception ex) { importErrors.Add(ConvertMetadataErrorToProxyGenerationError(metadataItem, ex)); } } } RemoveDuplicatedSchemaItems(metadataCollection, importErrors); CheckDuplicatedWsdlItems(metadataCollection, importErrors); return metadataCollection; } /// /// Convert metadata loading errors into proxy generation error messages /// ////// internal static ProxyGenerationError ConvertMetadataErrorToProxyGenerationError(MetadataFile metadataItem, Exception ex) { ProxyGenerationError generationError = null; if (ex is XmlSchemaException) { generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, (XmlSchemaException)ex); } else if (ex is XmlException) { generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, (XmlException)ex); } else if (ex is InvalidOperationException) { System.Xml.Schema.XmlSchemaException schemaException = ex.InnerException as System.Xml.Schema.XmlSchemaException; if (schemaException != null) { generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, schemaException); } else { System.Xml.XmlException xmlException = ex.InnerException as System.Xml.XmlException; if (xmlException != null) { generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, xmlException); } else { generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, (InvalidOperationException)ex); } } } else { generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, ex); } return generationError; } /// /// Remove duplicated schema items from the metadata collection /// ///private static void RemoveDuplicatedSchemaItems(List metadataCollection, IList importErrors) { Dictionary schemaList = new Dictionary (); // add independent schema files... foreach (MetadataSection metadataSection in metadataCollection) { if (metadataSection.Dialect == MetadataSection.XmlSchemaDialect) { XmlSchema schema = (XmlSchema)metadataSection.Metadata; schemaList.Add(schema, metadataSection); } } // add embedded files... foreach (MetadataSection metadataSection in metadataCollection) { if (metadataSection.Dialect == MetadataSection.ServiceDescriptionDialect) { System.Web.Services.Description.ServiceDescription wsdl = (System.Web.Services.Description.ServiceDescription)metadataSection.Metadata; foreach (XmlSchema schema in wsdl.Types.Schemas) { schema.SourceUri = wsdl.RetrievalUrl; schemaList.Add(schema, metadataSection); } } } IEnumerable duplicatedSchemas; SchemaMerger.MergeSchemas(schemaList.Keys, importErrors, out duplicatedSchemas); if (duplicatedSchemas != null) { foreach (XmlSchema schema in duplicatedSchemas) { Debug.Assert(schemaList.ContainsKey(schema), "The schema list should not contain any of the schemas returned in the duplicateSchemas..."); MetadataSection metadataSection = schemaList[schema]; if (metadataSection.Dialect == MetadataSection.XmlSchemaDialect) { metadataCollection.Remove(metadataSection); } else if (metadataSection.Dialect == MetadataSection.ServiceDescriptionDialect) { System.Web.Services.Description.ServiceDescription wsdl = (System.Web.Services.Description.ServiceDescription)metadataSection.Metadata; wsdl.Types.Schemas.Remove(schema); } } } } /// /// check all wsdl files, and generate error messages if one contract have multiple different specifications /// ///private static void CheckDuplicatedWsdlItems(IList metadataCollection, IList importErrors) { List wsdlFiles = new List (); foreach (MetadataSection metadataSection in metadataCollection) { if (metadataSection.Dialect == MetadataSection.ServiceDescriptionDialect) { System.Web.Services.Description.ServiceDescription wsdl = (System.Web.Services.Description.ServiceDescription)metadataSection.Metadata; wsdlFiles.Add(wsdl); } } WsdlInspector.CheckDuplicatedWsdlItems(wsdlFiles, importErrors); } /// /// Given a WSDL importer, a set of metadata files and a compile unit, import the metadata /// files. /// /// /// /// /// Errors encountered whie importing the model. Any new errors will be appended to this list. /// /// List of endpoints imported /// The collection of bindings imported /// The collection of contracts imported protected static void ImportWCFModel(WsdlImporter importer, System.CodeDom.CodeCompileUnit compileUnit, IListgenerationErrors, out List serviceEndpointList, out IEnumerable bindingCollection, out IEnumerable contractCollection) { // We want to remove soap1.2 endpoints for ASMX references, but we can't use the "normal" way // of using a IWsdlImportExtension to do so since BeforeImport is called too late (DevDiv 7857) // If DevDiv 7857 is fixed, we can remove the following two lines and instead add the // AsmxEndpointPickerExtension to the importer's wsdl import extensions... IWsdlImportExtension asmxFixerUpper = new AsmxEndpointPickerExtension(); asmxFixerUpper.BeforeImport(importer.WsdlDocuments, null, null); // NOTE: we should import Endpoint before Contracts, otherwise some information (related to binding) will be lost in the model (devdiv: 22396) serviceEndpointList = new List (); // // First we import all the endpoints (ports). This is required so that any WsdlImportExtension's BeforeImport // gets called before we actually try to import anything from the WSDL object model. // If we don't do this, we run into problems if any wsdl import extensions want to delete a specific port // and this port happens to be the first port we try to import (you can't interrupt the import) importer.ImportAllEndpoints(); // // We need to go through each endpoint element and "re-import" it in order to get the mapping // between the wsdlPort and the ServiceEndpoint... Importing the same endpoint twice is a no-op // as far as the endpoint collection is concerned - it is simply a hashtable lookup to retreive // the already generated information... // foreach (System.Web.Services.Description.ServiceDescription wsdlServiceDescription in importer.WsdlDocuments) { foreach (System.Web.Services.Description.Service wsdlService in wsdlServiceDescription.Services) { foreach (System.Web.Services.Description.Port servicePort in wsdlService.Ports) { try { ServiceEndpoint newEndpoint = importer.ImportEndpoint(servicePort); serviceEndpointList.Add(newEndpoint); } catch (InvalidOperationException) { // Invalid operation exceptions should already be in the errors collection for the importer, so we don't // need to add another generationError. The most probable cause for this is that the we failed to import // the endpoint... } catch (Exception ex) { // It is bad, because WsdlImporter.WsdlImportException is a private class generationErrors.Add(new ProxyGenerationError(ProxyGenerationError.GeneratorState.GenerateCode, wsdlServiceDescription.RetrievalUrl, ex)); } } } } bindingCollection = importer.ImportAllBindings(); System.Diagnostics.Debug.Assert(bindingCollection != null, "The importer should never return a NULL binding collection!"); contractCollection = importer.ImportAllContracts(); System.Diagnostics.Debug.Assert(contractCollection != null, "The importer should never return a NULL contract collection!"); foreach (MetadataConversionError error in importer.Errors) { generationErrors.Add(new ProxyGenerationError(error)); } } /// /// This function patches ServiceContractAttribute in the generated proxy code. It replaces all proxyNamespace in the attribute /// to configNamespace. The configNamespace does not depend on defaultNamespace of the project. /// /// /// ////// private static void PatchConfigurationNameInServiceContractAttribute(CodeCompileUnit proxyCodeUnit, string proxyNamespace, string configNamespace) { if (proxyNamespace == null) { proxyNamespace = String.Empty; } string proxyNamespaceHead = MakePeriodTerminatedNamespacePrefix(proxyNamespace); string configNamespaceHead = MakePeriodTerminatedNamespacePrefix(configNamespace); if (proxyCodeUnit != null) { foreach (CodeNamespace proxyCodeNamespace in proxyCodeUnit.Namespaces) { // Find the namespace we are patching... if (String.Equals(proxyNamespace, proxyCodeNamespace.Name, StringComparison.Ordinal)) { // ...and all types in each namespace... foreach (CodeTypeDeclaration typeDeclaration in proxyCodeNamespace.Types) { if (typeDeclaration.IsInterface) { // ...and each attribute on each interface... foreach (CodeAttributeDeclaration codeAttribute in typeDeclaration.CustomAttributes) { // find System.ServiceModel.ServiceContractAttribute attribute. if (String.Equals(codeAttribute.AttributeType.BaseType, typeof(System.ServiceModel.ServiceContractAttribute).FullName, StringComparison.Ordinal)) { foreach (CodeAttributeArgument argument in codeAttribute.Arguments) { if (String.Equals(argument.Name, "ConfigurationName", StringComparison.Ordinal)) { // we only fix the string here CodePrimitiveExpression valueExpression = argument.Value as CodePrimitiveExpression; if (valueExpression != null && valueExpression.Value is string) { valueExpression.Value = ReplaceNamespace(proxyNamespaceHead, configNamespaceHead, (string)valueExpression.Value); } } } } } } } } } } } /// /// Patch VB code for output parameters. /// /// Visual Basic doesn't support Out parameters - they are all generated as ByRef. /// Unfortunately, the CodeDom provider doesn't add an Out attribute to the ByRef /// parameters, so we have to do that ourselves... /// /// ///private static void PatchOutParametersInVB(CodeCompileUnit codeCompileUnit) { foreach (CodeNamespace codeNamespace in codeCompileUnit.Namespaces) { foreach (CodeTypeDeclaration codeClass in codeNamespace.Types) { PatchTypeDeclaration(codeClass); } } } /// /// Patch TypeDeclaration in VB code for output parameters /// /// ///private static void PatchTypeDeclaration(CodeTypeDeclaration codeClass) { foreach (CodeTypeMember member in codeClass.Members) { if (member is CodeTypeDeclaration) { // Recurse down in nested types... PatchTypeDeclaration((CodeTypeDeclaration)member); } else if (member is CodeMemberMethod) { CodeMemberMethod method = member as CodeMemberMethod; foreach (CodeParameterDeclarationExpression parameter in method.Parameters) { if (parameter.Direction == FieldDirection.Out) { // Make sure that all Out parameters have an attribute // // First check for explicit declaration to avoid adding duplicate attributes. if (!IsDefinedInCodeAttributeCollection(typeof(System.Runtime.InteropServices.OutAttribute), parameter.CustomAttributes)) { parameter.CustomAttributes.Add(OutAttribute); } } } } } } /// /// check whether code attribuate has already been declared. /// /// /// ////// private static bool IsDefinedInCodeAttributeCollection(Type type, CodeAttributeDeclarationCollection metadata) { foreach (CodeAttributeDeclaration attribute in metadata) { if (String.Equals(attribute.Name, type.FullName, StringComparison.Ordinal) || String.Equals(attribute.Name, type.Name, StringComparison.Ordinal)) { return true; } } return false; } /// /// Check whether it is VB language /// /// ////// private static bool IsVBCodeDomProvider(System.CodeDom.Compiler.CodeDomProvider codeDomProvider) { string fileExtension = codeDomProvider.FileExtension; try { string language = System.CodeDom.Compiler.CodeDomProvider.GetLanguageFromExtension(fileExtension); return String.Equals(language, VB_LANGUAGE_NAME, StringComparison.OrdinalIgnoreCase); } catch (System.Configuration.ConfigurationException) { // not defined extension return false; } } /// /// check whether HTTP Binding is used in those metadata files /// /// metadata files ////// private static bool ContainsHttpBindings(IEnumerable metadataCollection) { foreach (MetadataSection metadataSection in metadataCollection) { if (metadataSection.Dialect == MetadataSection.ServiceDescriptionDialect) { System.Web.Services.Description.ServiceDescription wsdlFile = (System.Web.Services.Description.ServiceDescription)metadataSection.Metadata; if (ContainsHttpBindings(wsdlFile)) { return true; } } } return false; } /// /// check whether HTTP Binding is used in one wsdl file /// /// one wsdl ////// internal static bool ContainsHttpBindings(System.Web.Services.Description.ServiceDescription wsdlFile) { foreach (System.Web.Services.Description.Binding binding in wsdlFile.Bindings) { foreach (object extension in binding.Extensions) { System.Web.Services.Description.HttpBinding httpBinding = extension as System.Web.Services.Description.HttpBinding; if (httpBinding != null) { return true; } } } return false; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ // // Copyright (C) Microsoft Corporation. All Rights Reserved. // //----------------------------------------------------------------------------- using System; using System.CodeDom; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Configuration; using System.Globalization; using System.Reflection; using System.Runtime.Serialization; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Configuration; using System.ServiceModel.Description; using System.Web.Services.Description; using System.Xml; using System.Xml.Schema; using System.Security.Permissions; #if WEB_EXTENSIONS_CODE using System.Web.Resources; #else using Microsoft.VSDesigner.Resources.Microsoft.VSDesigner; #endif /// /// The VSWCFServiceContractGenerator takes a SvcMap file and it's associated metadata, /// imports the metadata using a WsdlImporter and System.ServiceModel.ServiceContractGenerator /// that are configured according to the options set in the SvcMap file /// using Debug = System.Diagnostics.Debug; #if WEB_EXTENSIONS_CODE namespace System.Web.Compilation.WCFModel #else namespace Microsoft.VSDesigner.WCFModel #endif { ////// Proxy and configuration generator /// #if WEB_EXTENSIONS_CODE [PermissionSet(SecurityAction.LinkDemand, Name="FullTrust"), PermissionSet(SecurityAction.InheritanceDemand, Name="FullTrust")] internal class VSWCFServiceContractGenerator #else // We only check for CLS compliant for the public version of this class since the // compiler will complain about CLS compliance not being checked for non-public classes [CLSCompliant(true), PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust"), PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")] public class VSWCFServiceContractGenerator #endif { #region Private backing fields private const string VB_LANGUAGE_NAME = "vb"; ////// Collection to hold all bindings generated by this generator /// private IEnumerablebindingCollection; /// /// Collection to hold all contracts generated by this generator /// private IEnumerablecontractCollection; /// /// Collection to hold all endpoints generated by this generator /// private ListserviceEndpointList; /// /// Map from service endpoint to the channel endpoint that was actually imported /// private DictionaryserviceEndpointToChannelEndpointElementMap; /// /// List of contract types generate by this generator /// private ListproxyGeneratedContractTypes; /// /// The target compile unit that contains the proxy and data contracts /// private CodeCompileUnit targetCompileUnit; ////// Configuration object that we inserterd bindings and endpoints from the /// current service into. May be Null/Nothing. /// private System.Configuration.Configuration targetConfiguration; ////// Errors encountered while generating the proxy /// private IEnumerableproxyGenerationErrors; /// /// Errors encountered while importing the metadata.. /// private IListimportErrors; /// /// Helper property that is added to Out parameters for VB /// private static CodeAttributeDeclaration outAttribute; ////// version number for 3.5 framework /// private const int FRAMEWORK_VERSION_35 = 0x30005; ////// list of types which are new in the 3.5 framework. /// private static Type[] unsupportedTypesInFramework30 = new Type[] { typeof(DateTimeOffset), }; #endregion #region Public read-only properties ////// The collection of bindings generated by this generator /// ////// /// public IEnumerableBindingCollection { get { System.Diagnostics.Debug.Assert(bindingCollection != null); return bindingCollection; } } /// /// The collection of generated contract types /// public IEnumerableProxyGeneratedContractTypes { get { System.Diagnostics.Debug.Assert(proxyGeneratedContractTypes != null); return proxyGeneratedContractTypes; } } /// /// The collection of errors encountered while generating the /// proxy. For errors related to the metadata import, use the /// ImportErrors property /// public IEnumerableProxyGenerationErrors { get { System.Diagnostics.Debug.Assert(proxyGenerationErrors != null); return proxyGenerationErrors; } } /// /// The collection of errors encountered while importing metadata. /// For errors related to the proxy and config generation, use the /// ProxyGenerationErrors property /// public IEnumerableImportErrors { get { System.Diagnostics.Debug.Assert(importErrors != null); return importErrors; } } /// /// The collection of contracts imported by this generator /// ////// public IEnumerable ContractCollection { get { System.Diagnostics.Debug.Assert(contractCollection != null); return contractCollection; } } /// /// Collection of Endpoints in the service model generated by /// this generator /// ////// public IEnumerable EndpointCollection { get { System.Diagnostics.Debug.Assert(serviceEndpointList != null); return serviceEndpointList; } } /// /// Map from service endpoints to its corresponding channel endpoint configuration /// element /// public DictionaryEndpointMap { get { System.Diagnostics.Debug.Assert(serviceEndpointToChannelEndpointElementMap != null); return serviceEndpointToChannelEndpointElementMap; } } /// /// The configuratin into which we inject the bindings and endpoints. May be null/Nothing /// if no target configuration was provided. /// public System.Configuration.Configuration TargetConfiguration { get { // Note: it is valid for this to be NULL. Caller beware! return targetConfiguration; } } ////// CodeCompileUnit containing the generated data contracts, service contracts /// and WCF client. /// public CodeCompileUnit TargetCompileUnit { get { System.Diagnostics.Debug.Assert(targetCompileUnit != null); return targetCompileUnit; } } #endregion ////// Cached instance of an Out attribute that we use to patch up /// the codegen for VB projects (the VB code generates out parameters /// as ByRef) /// private static CodeAttributeDeclaration OutAttribute { get { if (outAttribute == null) { outAttribute = new CodeAttributeDeclaration(typeof(System.Runtime.InteropServices.OutAttribute).FullName); } return outAttribute; } } ////// protected constructor to block creating instance directly. /// /// /// /// May be null /// /// /// /// /// /// protected VSWCFServiceContractGenerator( ListimportErrors, CodeCompileUnit targetCompileUnit, System.Configuration.Configuration targetConfiguration, IEnumerable bindingCollection, IEnumerable contractCollection, List serviceEndpointList, Dictionary serviceEndpointToChannelEndpointElementMap, List proxyGeneratedContractTypes, IEnumerable proxyGenerationErrors) { if (importErrors == null) throw new ArgumentNullException("importErrors"); if (targetCompileUnit == null) throw new ArgumentNullException("targetCompileUnit"); // Please note - target configuration may be NULL if (bindingCollection == null) throw new ArgumentNullException("bindingCollection"); if (contractCollection == null) throw new ArgumentNullException("contractCollection"); if (serviceEndpointList == null) throw new ArgumentNullException("serviceEndpointList"); if (serviceEndpointToChannelEndpointElementMap == null) throw new ArgumentNullException("serviceEndpointToChannelEndpointElementMap"); if (proxyGeneratedContractTypes == null) throw new ArgumentNullException("proxyGeneratedContractTypes"); if (proxyGenerationErrors == null) throw new ArgumentNullException("proxyGenerationErrors"); this.importErrors = importErrors; this.targetCompileUnit = targetCompileUnit; this.targetConfiguration = targetConfiguration; this.bindingCollection = bindingCollection; this.contractCollection = contractCollection; this.serviceEndpointList = serviceEndpointList; this.serviceEndpointToChannelEndpointElementMap = serviceEndpointToChannelEndpointElementMap; this.proxyGeneratedContractTypes = proxyGeneratedContractTypes; this.proxyGenerationErrors = proxyGenerationErrors; } /// /// Factory method: generate code and return the resulting VSWCFServiceContractGenerator. /// /// /// The SvcMapFile that lists the metadata and generation options for the service reference. /// /// /// Configuration from which we are going to pick up WSDL and policy importer extensions as well /// as custom MEX bindings for metadata download. May be Null/Nothing. /// /// /// CodeDom provider that is to be used to generate the client code. /// /// /// CLR namespace in which to generate the client code. /// /// /// The configuration into which we will put bindings/endpoints for this service /// reference. May be Null/Nothing. /// /// /// The namespace that is to be used in configuration for this service reference. /// /// /// Service provider that we'll pass on to import extensions that accept our site:ing /// mechanism /// /// /// Type loader that can be used to find reference assemblies and/or resolve shared service and /// data contract types. /// /// /// The target framework version number. The higher 16 bits contains the major version number, and low 16 bits contains minor version number. /// /// /// Schema importer extension to be used for typed datasets. /// ////// A VSWCFServiceContractGenerator instance that contains the result of the generation. To get /// hold of the generated information, you can query it's properties. /// public static VSWCFServiceContractGenerator GenerateCodeAndConfiguration(SvcMapFile svcMapFile, System.Configuration.Configuration toolConfiguration, System.CodeDom.Compiler.CodeDomProvider codeDomProvider, string proxyNamespace, System.Configuration.Configuration targetConfiguration, string configurationNamespace, IServiceProvider serviceProviderForImportExtensions, IContractGeneratorReferenceTypeLoader typeLoader, int targetFrameworkVersion, System.Type typedDataSetSchemaImporterExtension) { if (svcMapFile == null) throw new ArgumentNullException("svcMapFile"); if (codeDomProvider == null) throw new ArgumentNullException("codeDomProvider"); if (typedDataSetSchemaImporterExtension == null) throw new ArgumentNullException("typedDataSetSchemaImporterExtension"); ListimportErrors = new List (); List proxyGenerationErrors = new List (); CodeCompileUnit targetCompileUnit = new CodeCompileUnit(); WsdlImporter wsdlImporter = CreateWsdlImporter(svcMapFile, toolConfiguration, targetCompileUnit, codeDomProvider, proxyNamespace, serviceProviderForImportExtensions, typeLoader, targetFrameworkVersion, importErrors, typedDataSetSchemaImporterExtension); ServiceContractGenerator contractGenerator = CreateContractGenerator(svcMapFile.ClientOptions, wsdlImporter, targetCompileUnit, proxyNamespace, targetConfiguration, typeLoader, targetFrameworkVersion, importErrors); try { List serviceEndpointList = new List (); IEnumerable bindingCollection; IEnumerable contractCollection; ImportWCFModel(wsdlImporter, targetCompileUnit, importErrors, out serviceEndpointList, out bindingCollection, out contractCollection); Dictionary serviceEndpointToChannelEndpointElementMap; List proxyGeneratedContractTypes; GenerateProxy(contractGenerator, targetCompileUnit, proxyNamespace, configurationNamespace, contractCollection, bindingCollection, serviceEndpointList, proxyGenerationErrors, out serviceEndpointToChannelEndpointElementMap, out proxyGeneratedContractTypes); if (IsVBCodeDomProvider(codeDomProvider)) { PatchOutParametersInVB(targetCompileUnit); } return new VSWCFServiceContractGenerator(importErrors, targetCompileUnit, targetConfiguration, bindingCollection, contractCollection, serviceEndpointList, serviceEndpointToChannelEndpointElementMap, proxyGeneratedContractTypes, proxyGenerationErrors); } catch (Exception ex) { // fatal error... (workaround for bug #135242) // We want to convert fatal error exception to a normal code generator error message, // so the user could find information from pervious errors to find KB topic. proxyGenerationErrors.Add(new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, ex, false)); return new VSWCFServiceContractGenerator(importErrors, new CodeCompileUnit(), targetConfiguration, new List (), new List (), new List (), new Dictionary (), new List (), proxyGenerationErrors); } } /// /// Instantiate and configure a ServiceContractGenerator to be used for code and config /// generation. /// /// /// Options set in the SvcMap file to control the code/config generation. /// /// /// The WsdlImporter that is to be used to import the metadata for this service reference. /// /// /// Compile unit into which we will generate the client code /// /// /// The CLR namespace into which we will generate the client code. /// /// /// Optional configuration into which we will generate the endpoints/bindings corresponding /// to this service reference. May be Null/Nothing, in which case we will not generate config. /// /// /// Type loader that can be used to find reference assemblies and/or resolve shared service and /// data contract types. /// /// /// The target framework version number. The higher 16 bits contains the major version number, and low 16 bits contains minor version number. /// /// /// The list into which we will add any errors while importing the metadata. /// ///protected static ServiceContractGenerator CreateContractGenerator(ClientOptions proxyOptions, WsdlImporter wsdlImporter, CodeCompileUnit targetCompileUnit, string proxyNamespace, System.Configuration.Configuration targetConfiguration, IContractGeneratorReferenceTypeLoader typeLoader, int targetFrameworkVersion, IList importErrors) { ServiceContractGenerator contractGenerator = new ServiceContractGenerator(targetCompileUnit, targetConfiguration); // We want to generate all types into the proxy namespace CLR namespace. We indicate // this by adding a namespace mapping from all XML namespaces ("*") to the namespace // the caller told us to generate the client code in. contractGenerator.NamespaceMappings.Add("*", proxyNamespace); if (proxyOptions.GenerateInternalTypes) { contractGenerator.Options |= ServiceContractGenerationOptions.InternalTypes; } else { contractGenerator.Options &= ~ServiceContractGenerationOptions.InternalTypes; } if (proxyOptions.GenerateAsynchronousMethods) { contractGenerator.Options |= ServiceContractGenerationOptions.AsynchronousMethods; if (targetFrameworkVersion >= FRAMEWORK_VERSION_35) { contractGenerator.Options |= ServiceContractGenerationOptions.EventBasedAsynchronousMethods; } } else { contractGenerator.Options &= ~ServiceContractGenerationOptions.AsynchronousMethods; } if (proxyOptions.GenerateMessageContracts) { contractGenerator.Options |= ServiceContractGenerationOptions.TypedMessages; } else { contractGenerator.Options &= ~ServiceContractGenerationOptions.TypedMessages; } // If we have a type loader, we tell the contract generator and wsdl importer about // all shared types and assemblies that we've specified in the proxy options... if (typeLoader != null) { foreach (ContractMapping mapping in proxyOptions.ServiceContractMappingList) { try { Type sharedType = typeLoader.LoadType(mapping.TypeName); // verify that the type is shareable - if not, we generate an error... if (!IsTypeShareable(sharedType)) { importErrors.Add( new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, new FormatException(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_SharedTypeMustBePublic, mapping.TypeName))) ); continue; } // Get a contract description corresponding to the type we wanted to share ContractDescription contract = ContractDescription.GetContract(sharedType); if (!String.Equals(mapping.Name, contract.Name, StringComparison.Ordinal) || !String.Equals(mapping.TargetNamespace, contract.Namespace, StringComparison.Ordinal)) { // mismatch importErrors.Add( new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, new FormatException(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_ServiceContractMappingMissMatch, mapping.TypeName, contract.Namespace, contract.Name, mapping.TargetNamespace, mapping.Name))) ); } XmlQualifiedName qname = new XmlQualifiedName(contract.Name, contract.Namespace); wsdlImporter.KnownContracts.Add(qname, contract); contractGenerator.ReferencedTypes.Add(contract, sharedType); } catch (Exception ex) { importErrors.Add(new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, ex)); } } } foreach (NamespaceMapping namespaceMapping in proxyOptions.NamespaceMappingList) { contractGenerator.NamespaceMappings.Add(namespaceMapping.TargetNamespace, namespaceMapping.ClrNamespace); } return contractGenerator; } /// /// Generate Proxy Code and (if available) configuration /// /// The contract generator to use /// Compile unit into which we should generate the client code /// CLR namespace into which we should generate the client code /// Namespace to use in configuration /// The contracts for which we should generate code and optionally config /// The bindings we should generate config for /// The endpoints we should generate config for /// A list of errors encountered while generating the client /// Map from service endpoint to the configuration element for the endpoint /// The generated contract types protected static void GenerateProxy(ServiceContractGenerator contractGenerator, CodeCompileUnit targetCompileUnit, string proxyNamespace, string configurationNamespace, IEnumerablecontractCollection, IEnumerable bindingCollection, List serviceEndpointList, IList proxyGenerationErrors, out Dictionary serviceEndpointToChannelEndpointElementMap, out List proxyGeneratedContractTypes) { // Parameter checking if (serviceEndpointList == null) throw new ArgumentNullException("serviceEndpointList"); if (bindingCollection == null) throw new ArgumentNullException("bindingCollection"); if (contractCollection == null) throw new ArgumentNullException("contractCollection"); if (proxyGenerationErrors == null) throw new ArgumentNullException("proxyGenerationErrors"); proxyGeneratedContractTypes = new List (); serviceEndpointToChannelEndpointElementMap = new Dictionary (); try { foreach (ContractDescription contract in contractCollection) { CodeTypeReference typeReference = contractGenerator.GenerateServiceContractType(contract); if (typeReference != null) { // keep the (targetNamespace, portType) -> CLR type map table... string baseType = typeReference.BaseType; GeneratedContractType generatedType = new GeneratedContractType(contract.Namespace, contract.Name, baseType, baseType); proxyGeneratedContractTypes.Add(generatedType); } } // We should only import the Binding & Endpoints if there is a configuration storage... if (contractGenerator.Configuration != null) { foreach (ServiceEndpoint endpoint in serviceEndpointList) { ChannelEndpointElement endpointElement = null; contractGenerator.GenerateServiceEndpoint(endpoint, out endpointElement); serviceEndpointToChannelEndpointElementMap[endpoint] = endpointElement; } foreach (System.ServiceModel.Channels.Binding bindingDescription in bindingCollection) { string bindingSectionName = null; string bindingConfigurationName = null; // Generate binding will change the state of the contractGenerator... contractGenerator.GenerateBinding(bindingDescription, out bindingSectionName, out bindingConfigurationName); } } PatchConfigurationName(proxyNamespace, configurationNamespace, proxyGeneratedContractTypes, serviceEndpointToChannelEndpointElementMap.Values, targetCompileUnit); } finally { foreach (MetadataConversionError error in contractGenerator.Errors) { proxyGenerationErrors.Add(new ProxyGenerationError(error)); } } } /// /// Create appropriate XmlSerializerImportOptions for the generator /// /// Options for the code/config generation /// Compile unit we are going to generate the client code in /// CodeDom provider for the language we are using /// CLR namespace we'll put the client code in ///protected static XmlSerializerImportOptions CreateXmlSerializerImportOptions( ClientOptions proxyOptions, CodeCompileUnit targetCompileUnit, System.CodeDom.Compiler.CodeDomProvider codeDomProvider, string proxyNamespace, System.Type typedDataSetSchemaImporterExtension) { System.ServiceModel.Channels.XmlSerializerImportOptions xmlSerializerOptions = new XmlSerializerImportOptions(targetCompileUnit); System.Web.Services.Description.WebReferenceOptions webReferenceOptions = new System.Web.Services.Description.WebReferenceOptions(); webReferenceOptions.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateProperties | System.Xml.Serialization.CodeGenerationOptions.GenerateOrder; if (proxyOptions.EnableDataBinding) { webReferenceOptions.CodeGenerationOptions |= System.Xml.Serialization.CodeGenerationOptions.EnableDataBinding; } webReferenceOptions.SchemaImporterExtensions.Add(typedDataSetSchemaImporterExtension.AssemblyQualifiedName); webReferenceOptions.SchemaImporterExtensions.Add(typeof(System.Data.DataSetSchemaImporterExtension).AssemblyQualifiedName); /* */ xmlSerializerOptions.WebReferenceOptions = webReferenceOptions; xmlSerializerOptions.CodeProvider = codeDomProvider; xmlSerializerOptions.ClrNamespace = proxyNamespace; return xmlSerializerOptions; } /// /// Create an appropriate XsdDataContractImporter for the generator /// /// Code/config generation options to use /// CodeCompileUnit into which we will generate the client code /// CodeDomProvider for the language we will use to generate the client /// CLR namespace in which the client code will be generated /// Service used to resolve type/assembly names (strings) to actual Types and Assemblies /// Targetted Framework version number /// List of errors encountered. New errors will be added to this list ///protected static XsdDataContractImporter CreateDataContractImporter( ClientOptions proxyOptions, CodeCompileUnit targetCompileUnit, System.CodeDom.Compiler.CodeDomProvider codeDomProvider, string proxyNamespace, IContractGeneratorReferenceTypeLoader typeLoader, int targetFrameworkVersion, IList importErrors) { System.Runtime.Serialization.XsdDataContractImporter xsdDataContractImporter = new System.Runtime.Serialization.XsdDataContractImporter(targetCompileUnit); System.Runtime.Serialization.ImportOptions options = new System.Runtime.Serialization.ImportOptions(); options.CodeProvider = codeDomProvider; // We specify that we want to generate all types from all XML namespaces into // our proxy namespace. By default, each XML namespace get's its own CLR namespace options.Namespaces.Add("*", proxyNamespace); options.GenerateInternal = proxyOptions.GenerateInternalTypes; options.GenerateSerializable = proxyOptions.GenerateSerializableTypes; options.EnableDataBinding = proxyOptions.EnableDataBinding; options.ImportXmlType = proxyOptions.ImportXmlTypes; if (typeLoader != null) { IEnumerable referencedTypes = LoadSharedDataContractTypes(proxyOptions, typeLoader, targetFrameworkVersion, importErrors); if (referencedTypes != null) { foreach (Type sharedType in referencedTypes) { options.ReferencedTypes.Add(sharedType); } } IEnumerable referencedCollectionTypes = LoadSharedCollectionTypes(proxyOptions, typeLoader, importErrors); if (referencedCollectionTypes != null) { foreach (Type collectionType in referencedCollectionTypes) { options.ReferencedCollectionTypes.Add(collectionType); } } } foreach (NamespaceMapping namespaceMapping in proxyOptions.NamespaceMappingList) { options.Namespaces.Add(namespaceMapping.TargetNamespace, namespaceMapping.ClrNamespace); } xsdDataContractImporter.Options = options; return xsdDataContractImporter; } /// /// Load DataContract types which could be used in the code generator (shared types) /// /// Options controlling the generation /// Type loader to resolve referenced assemblies and types /// Targetted Framework version number /// Errors encountered while loading the shared data contracts ////// A list of CLR types from referenced assemblies and/or specific types that we want to share /// ///protected static IEnumerable LoadSharedDataContractTypes( ClientOptions proxyOptions, IContractGeneratorReferenceTypeLoader typeLoader, int targetFrameworkVersion, IList importErrors) { if (typeLoader == null) throw new ArgumentNullException("typeLoader"); // the value in sharedTypeTable is why we add this type in the shared type list. // if it is only added because it is in the referenced assembly, the value will be null, otherwise it contains the entry in the type inclusion list // if the type is also in the exclusion list, we will report an error if the type is comming from the inclusion list, but no error if it comes from a referenced assembly only. Dictionary sharedTypeTable = new Dictionary (); // load all types in referencedAssemblies IEnumerable referencedAssemblies = LoadReferenedAssemblies(proxyOptions, typeLoader, importErrors); if (referencedAssemblies != null) { foreach (Assembly referencedAssembly in referencedAssemblies) { try { foreach (Type typeInAssembly in referencedAssembly.GetTypes()) { if (IsTypeShareable(typeInAssembly)) { sharedTypeTable.Add(typeInAssembly, null); } } } catch (Exception ex) { // fail to load one type in an assembly: warning message importErrors.Add( new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, ex, true)); } } } // load types in DataContractTypeList foreach (ReferencedType referencedType in proxyOptions.ReferencedDataContractTypeList) { try { Type sharedType = typeLoader.LoadType(referencedType.TypeName); // verify... if (!IsTypeShareable(sharedType)) { importErrors.Add( new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, new FormatException(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_SharedTypeMustBePublic, referencedType.TypeName))) ); continue; } sharedTypeTable[sharedType] = referencedType; } catch (Exception ex) { importErrors.Add(new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, ex)); } } // remove excluded types foreach (ReferencedType excludedType in proxyOptions.ExcludedTypeList) { try { Type sharedType = typeLoader.LoadType(excludedType.TypeName); if (sharedTypeTable.ContainsKey(sharedType)) { if (sharedTypeTable[sharedType] != null) { // error message importErrors.Add(new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, new Exception(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_DataContractExcludedAndIncluded, excludedType.TypeName)))); } sharedTypeTable.Remove(sharedType); } } catch (Exception ex) { // waring message for excludedTypes importErrors.Add(new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, ex, true)); } } // remove unsupported types foreach (Type unsupportedType in GetUnsupportedTypes(targetFrameworkVersion)) { sharedTypeTable.Remove(unsupportedType); } return sharedTypeTable.Keys; } /// /// Get list of types which are not supported in the targetted framework. /// /// Targetted Framework version number ////// private static IEnumerable GetUnsupportedTypes(int targetFrameworkVersion) { if (targetFrameworkVersion < FRAMEWORK_VERSION_35) { // NOTE: do we need load those types with typeLoader? return unsupportedTypesInFramework30; } return new Type[0]; } /// /// Ensure that the ConfigurationName attribute on service contracts and the channel endpoint elements all agree on the /// name of the service contract. /// We want to avoid having root/default namespace values persisted in config, since that would require us /// to update config whenever the default/root namespace changes, so we make sure that we exclude it /// from the ConfigurationName attribute and the channel endpoint element we generate. /// /// For VB, the root namespace is not actually present in the generated code, so we typically don't have to /// do anything (the configuration and proxy namespaces are equal) but for C#, we need to strip out the /// default namespace. /// /// /// CLR namespace into which we will generate the service in the CodeCompileUnit /// /// /// The namespace that we expect to use in configuration. /// /// /// The contracts that we have generated /// /// /// All channel endpoints we have generated /// /// /// The compile unit into which we generated the client /// private static void PatchConfigurationName( string proxyNamespace, string configNamespace, IEnumerablegeneratedContracts, IEnumerable endpoints, CodeCompileUnit targetCompileUnit ) { // Since the name has to match between configuration and the name we put in the ConfigurationName // attribute in code, we may have some patching to do - but only if the proxy namespace is not equal // to the configuration namespace... if (configNamespace != null && !configNamespace.Equals(proxyNamespace, StringComparison.Ordinal)) { string proxyNamespaceHead = MakePeriodTerminatedNamespacePrefix(proxyNamespace); string configNamespaceHead = MakePeriodTerminatedNamespacePrefix(configNamespace); // We need to fix up the configuration name for all generated contracts... foreach (GeneratedContractType contract in generatedContracts) { contract.ConfigurationName = ReplaceNamespace(proxyNamespaceHead, configNamespaceHead, contract.ConfigurationName); } // ..and we need to fix up all elements in config... foreach (ChannelEndpointElement endpoint in endpoints) { endpoint.Contract = ReplaceNamespace(proxyNamespaceHead, configNamespaceHead, endpoint.Contract); } // ...and all ConfigurationName values in service contract attributes in the generated code as well... PatchConfigurationNameInServiceContractAttribute(targetCompileUnit, proxyNamespace, configNamespace); } } /// /// If the type name begins with the namespace specified in originalNamespace, replace the namespace /// for the given type name with the namespace specified in the replacementNamespace parameter. /// /// /// Original namespace to look for. /// Must either be an empty string ("") or end with a period (".") /// /// /// Namespace to replace original namespace with /// Muse either be an empty string ("") or end with a period... /// /// Typename on which to do the replacement ////// The new type name (potentially the same as passed in) /// private static string ReplaceNamespace(string originalNamespace, string replacementNamespace, string typeName) { Debug.Assert(originalNamespace.Length == 0 || originalNamespace.EndsWith(".", StringComparison.Ordinal)); Debug.Assert(replacementNamespace.Length == 0 || replacementNamespace.EndsWith(".", StringComparison.Ordinal)); Debug.Assert(typeName != null); if (typeName.StartsWith(originalNamespace, StringComparison.Ordinal)) { // Strip out the original namespace and replace it with the new namespace return replacementNamespace + typeName.Substring(originalNamespace.Length); } else { return typeName; } } ////// Given the namespace, return either an empty string (if the given namespace was NULL or emtpy) /// or a period-terminated (".") string. /// /// ////// Either an empty string or a string that ends with a period (".") /// Can never return Null... /// private static string MakePeriodTerminatedNamespacePrefix(string ns) { if (String.IsNullOrEmpty(ns)) { return ""; } else if (!ns.EndsWith(".", StringComparison.Ordinal)) { return ns + "."; } else { return ns; } } ////// Determine if a type can be shared. /// /// In order for a type to be shareable for service references, it has to be a /// public type... /// /// ///private static bool IsTypeShareable(Type t) { if (t == null) { System.Diagnostics.Debug.Fail("Why are you asking if a NULL type is shareable?"); return false; } return t.IsPublic || t.IsNestedPublic; } /// /// Load referenced assemblies /// /// /// /// ////// private static IEnumerable LoadReferenedAssemblies(ClientOptions proxyOptions, IContractGeneratorReferenceTypeLoader typeLoader, IList importErrors) { List referencedAssemblies = new List (); if (proxyOptions.ReferenceAllAssemblies) { try { IEnumerable loadingErrors = null; IEnumerable allAssemblies = null; typeLoader.LoadAllAssemblies(out allAssemblies, out loadingErrors); if (loadingErrors != null) { // treat as warning messages foreach (Exception ex in loadingErrors) { importErrors.Add(new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, ex, true)); } } if (allAssemblies != null) { referencedAssemblies.AddRange(allAssemblies); } } catch (Exception ex) { importErrors.Add(new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, ex)); } } foreach (ReferencedAssembly referencedAssembly in proxyOptions.ReferencedAssemblyList) { try { Assembly refAssembly = typeLoader.LoadAssembly(referencedAssembly.AssemblyName); if (refAssembly != null && !referencedAssemblies.Contains(refAssembly)) { referencedAssemblies.Add(refAssembly); } } catch (Exception ex) { importErrors.Add(new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, ex)); } } return referencedAssemblies; } /// /// Load the list of types that we have specified as collection types in our client options. /// The collection types will be used to generate collections in the data contracts. /// /// Options specifying the list of collection types /// Type loader that resolves type names to actual CLR types /// Errors encountered while loading the collection types ////// protected static IEnumerable LoadSharedCollectionTypes(ClientOptions proxyOptions, IContractGeneratorReferenceTypeLoader typeLoader, IList importErrors) { List referencedCollectionTypes = new List (); foreach (ReferencedCollectionType referencedCollectionMapping in proxyOptions.CollectionMappingList) { try { Type collectionType = typeLoader.LoadType(referencedCollectionMapping.TypeName); // verify... if (!IsTypeShareable(collectionType)) { importErrors.Add( new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, new FormatException(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_SharedTypeMustBePublic, referencedCollectionMapping.TypeName))) ); continue; } referencedCollectionTypes.Add(collectionType); } catch (Exception ex) { importErrors.Add(new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, ex)); } } return referencedCollectionTypes; } /// /// Create an appropriate WsdlImporter for the generator /// /// /// /// /// /// /// /// Targetted Framework version number /// /// ///protected static WsdlImporter CreateWsdlImporter(SvcMapFile svcMapFile, System.Configuration.Configuration toolConfiguration, CodeCompileUnit targetCompileUnit, System.CodeDom.Compiler.CodeDomProvider codeDomProvider, string targetNamespace, IServiceProvider serviceProviderForImportExtensions, IContractGeneratorReferenceTypeLoader typeLoader, int targetFrameworkVersion, IList importErrors, System.Type typedDataSetSchemaImporterExtension) { List metadataSections = CollectMetadataDocuments(svcMapFile.MetadataList, importErrors); WsdlImporter importer = null; ClientOptions.ProxySerializerType serializerType = svcMapFile.ClientOptions.Serializer; if (serializerType == ClientOptions.ProxySerializerType.Auto && ContainsHttpBindings(metadataSections)) { // NOTE: HTTP Get/Post binding indicates an old web service. We use XmlSerializer to prevent generating dup classes. // Please check devdiv bug 94078 serializerType = ClientOptions.ProxySerializerType.XmlSerializer; } if (toolConfiguration != null) { ServiceModelSectionGroup serviceModelSection = ServiceModelSectionGroup.GetSectionGroup(toolConfiguration); if (serviceModelSection != null) { Collection wsdlImportExtensions = serviceModelSection.Client.Metadata.LoadWsdlImportExtensions(); Collection policyImportExtensions = serviceModelSection.Client.Metadata.LoadPolicyImportExtensions(); // If we have specified a specific serializer to use, we remove // the other serializer... switch (serializerType) { case ClientOptions.ProxySerializerType.DataContractSerializer: RemoveExtension(typeof(XmlSerializerMessageContractImporter), wsdlImportExtensions); break; case ClientOptions.ProxySerializerType.XmlSerializer: RemoveExtension(typeof(DataContractSerializerMessageContractImporter), wsdlImportExtensions); break; case ClientOptions.ProxySerializerType.Auto: break; default: System.Diagnostics.Debug.Fail("Unknown serializer"); break; } ProvideImportExtensionsWithContextInformation(svcMapFile, serviceProviderForImportExtensions, wsdlImportExtensions, policyImportExtensions); // Create Importer... importer = new WsdlImporter(new MetadataSet(metadataSections), policyImportExtensions, wsdlImportExtensions); } } if (importer == null) { importer = new WsdlImporter(new MetadataSet(metadataSections)); } // DevDiv 124333 - Always add DataContract importer (even if we are in XmlSerializerMode) to // enable importing Fault contracts... importer.State.Add(typeof(System.Runtime.Serialization.XsdDataContractImporter), CreateDataContractImporter(svcMapFile.ClientOptions, targetCompileUnit, codeDomProvider, targetNamespace, typeLoader, targetFrameworkVersion, importErrors)); if (serializerType != ClientOptions.ProxySerializerType.DataContractSerializer) { importer.State.Add(typeof(System.ServiceModel.Channels.XmlSerializerImportOptions), CreateXmlSerializerImportOptions(svcMapFile.ClientOptions, targetCompileUnit, codeDomProvider, targetNamespace, typedDataSetSchemaImporterExtension)); } // Read the UseSerializerForFaults from Reference.svcmap, create a FaultImportOptions using this information // and pass it to WSDL Importer. FaultImportOptions faultOptions = new FaultImportOptions(); faultOptions.UseMessageFormat = svcMapFile.ClientOptions.UseSerializerForFaults; importer.State.Add(typeof(System.ServiceModel.FaultImportOptions), faultOptions); // Read the WrappedOptions from Reference.svcmap, create a WrappedOptions using this information // and pass it to WSDL Importer. WrappedOptions wrappedOptions = new WrappedOptions(); wrappedOptions.WrappedFlag = svcMapFile.ClientOptions.Wrapped; importer.State.Add(typeof(System.ServiceModel.Channels.WrappedOptions), wrappedOptions); return importer; } /// /// Look through all the import extensions to see if any of them want access to /// the service reference's extension files. They tell us this by implementing /// the interface IWcfReferenceReceiveContextInformation. /// /// /// /// /// internal static void ProvideImportExtensionsWithContextInformation(SvcMapFile svcMapFile, IServiceProvider serviceProviderForImportExtensions, IEnumerablewsdlImportExtensions, IEnumerable policyImportExtensions) { // Only make this copy if we need to (not the mainline case) Dictionary extensionFileContents = null; foreach (IWsdlImportExtension wsdlImportExtension in wsdlImportExtensions) { System.Web.Compilation.IWcfReferenceReceiveContextInformation receiveContext = wsdlImportExtension as System.Web.Compilation.IWcfReferenceReceiveContextInformation; if (receiveContext != null) { if (extensionFileContents == null) { extensionFileContents = CreateDictionaryOfCopiedExtensionFiles(svcMapFile); } receiveContext.ReceiveImportContextInformation( extensionFileContents, serviceProviderForImportExtensions); } } foreach (IPolicyImportExtension policyImportExtension in policyImportExtensions) { System.Web.Compilation.IWcfReferenceReceiveContextInformation receiveContext = policyImportExtension as System.Web.Compilation.IWcfReferenceReceiveContextInformation; if (receiveContext != null) { if (extensionFileContents == null) { extensionFileContents = CreateDictionaryOfCopiedExtensionFiles(svcMapFile); } receiveContext.ReceiveImportContextInformation( extensionFileContents, serviceProviderForImportExtensions); } } } /// /// Remove specific wsdl importer extension /// /// /// The extension to remove /// /// /// The collection to remove the extension from /// ////// private static void RemoveExtension(Type extensionType, Collection wsdlImportExtensions) { Debug.Assert(wsdlImportExtensions != null); for (int i = 0; i < wsdlImportExtensions.Count; i++) { if (wsdlImportExtensions[i].GetType() == extensionType) wsdlImportExtensions.RemoveAt(i); } } /// /// Creates a dictionary containing a copy of the contents of all of the extension files /// ///private static Dictionary CreateDictionaryOfCopiedExtensionFiles(SvcMapFile svcMapFile) { Dictionary extensionFileContents = new Dictionary (); foreach (ExtensionFile extensionFile in svcMapFile.Extensions) { // If the extension file was not successfully loaded, do not include it in the // collection. Users are more likely to expect that the extension file won't // be in the collection on an error than they are to assume they have to check // if the byte array we return is null or not. if (extensionFile.ContentBuffer != null && extensionFile.IsBufferValid) { extensionFileContents.Add(extensionFile.Name, (byte[])extensionFile.ContentBuffer.Clone()); } } return extensionFileContents; } /// /// Merge metadata files to prepare code generation /// ///metadata collection ///protected static List CollectMetadataDocuments(IEnumerable metadataList, IList importErrors) { List metadataCollection = new List (); foreach (MetadataFile metadataItem in metadataList) { if (!metadataItem.Ignore) { try { MetadataSection metadataSection = metadataItem.CreateMetadataSection(); if (metadataSection != null) { metadataCollection.Add(metadataSection); } } catch (Exception ex) { importErrors.Add(ConvertMetadataErrorToProxyGenerationError(metadataItem, ex)); } } } RemoveDuplicatedSchemaItems(metadataCollection, importErrors); CheckDuplicatedWsdlItems(metadataCollection, importErrors); return metadataCollection; } /// /// Convert metadata loading errors into proxy generation error messages /// ////// internal static ProxyGenerationError ConvertMetadataErrorToProxyGenerationError(MetadataFile metadataItem, Exception ex) { ProxyGenerationError generationError = null; if (ex is XmlSchemaException) { generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, (XmlSchemaException)ex); } else if (ex is XmlException) { generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, (XmlException)ex); } else if (ex is InvalidOperationException) { System.Xml.Schema.XmlSchemaException schemaException = ex.InnerException as System.Xml.Schema.XmlSchemaException; if (schemaException != null) { generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, schemaException); } else { System.Xml.XmlException xmlException = ex.InnerException as System.Xml.XmlException; if (xmlException != null) { generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, xmlException); } else { generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, (InvalidOperationException)ex); } } } else { generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, ex); } return generationError; } /// /// Remove duplicated schema items from the metadata collection /// ///private static void RemoveDuplicatedSchemaItems(List metadataCollection, IList importErrors) { Dictionary schemaList = new Dictionary (); // add independent schema files... foreach (MetadataSection metadataSection in metadataCollection) { if (metadataSection.Dialect == MetadataSection.XmlSchemaDialect) { XmlSchema schema = (XmlSchema)metadataSection.Metadata; schemaList.Add(schema, metadataSection); } } // add embedded files... foreach (MetadataSection metadataSection in metadataCollection) { if (metadataSection.Dialect == MetadataSection.ServiceDescriptionDialect) { System.Web.Services.Description.ServiceDescription wsdl = (System.Web.Services.Description.ServiceDescription)metadataSection.Metadata; foreach (XmlSchema schema in wsdl.Types.Schemas) { schema.SourceUri = wsdl.RetrievalUrl; schemaList.Add(schema, metadataSection); } } } IEnumerable duplicatedSchemas; SchemaMerger.MergeSchemas(schemaList.Keys, importErrors, out duplicatedSchemas); if (duplicatedSchemas != null) { foreach (XmlSchema schema in duplicatedSchemas) { Debug.Assert(schemaList.ContainsKey(schema), "The schema list should not contain any of the schemas returned in the duplicateSchemas..."); MetadataSection metadataSection = schemaList[schema]; if (metadataSection.Dialect == MetadataSection.XmlSchemaDialect) { metadataCollection.Remove(metadataSection); } else if (metadataSection.Dialect == MetadataSection.ServiceDescriptionDialect) { System.Web.Services.Description.ServiceDescription wsdl = (System.Web.Services.Description.ServiceDescription)metadataSection.Metadata; wsdl.Types.Schemas.Remove(schema); } } } } /// /// check all wsdl files, and generate error messages if one contract have multiple different specifications /// ///private static void CheckDuplicatedWsdlItems(IList metadataCollection, IList importErrors) { List wsdlFiles = new List (); foreach (MetadataSection metadataSection in metadataCollection) { if (metadataSection.Dialect == MetadataSection.ServiceDescriptionDialect) { System.Web.Services.Description.ServiceDescription wsdl = (System.Web.Services.Description.ServiceDescription)metadataSection.Metadata; wsdlFiles.Add(wsdl); } } WsdlInspector.CheckDuplicatedWsdlItems(wsdlFiles, importErrors); } /// /// Given a WSDL importer, a set of metadata files and a compile unit, import the metadata /// files. /// /// /// /// /// Errors encountered whie importing the model. Any new errors will be appended to this list. /// /// List of endpoints imported /// The collection of bindings imported /// The collection of contracts imported protected static void ImportWCFModel(WsdlImporter importer, System.CodeDom.CodeCompileUnit compileUnit, IListgenerationErrors, out List serviceEndpointList, out IEnumerable bindingCollection, out IEnumerable contractCollection) { // We want to remove soap1.2 endpoints for ASMX references, but we can't use the "normal" way // of using a IWsdlImportExtension to do so since BeforeImport is called too late (DevDiv 7857) // If DevDiv 7857 is fixed, we can remove the following two lines and instead add the // AsmxEndpointPickerExtension to the importer's wsdl import extensions... IWsdlImportExtension asmxFixerUpper = new AsmxEndpointPickerExtension(); asmxFixerUpper.BeforeImport(importer.WsdlDocuments, null, null); // NOTE: we should import Endpoint before Contracts, otherwise some information (related to binding) will be lost in the model (devdiv: 22396) serviceEndpointList = new List (); // // First we import all the endpoints (ports). This is required so that any WsdlImportExtension's BeforeImport // gets called before we actually try to import anything from the WSDL object model. // If we don't do this, we run into problems if any wsdl import extensions want to delete a specific port // and this port happens to be the first port we try to import (you can't interrupt the import) importer.ImportAllEndpoints(); // // We need to go through each endpoint element and "re-import" it in order to get the mapping // between the wsdlPort and the ServiceEndpoint... Importing the same endpoint twice is a no-op // as far as the endpoint collection is concerned - it is simply a hashtable lookup to retreive // the already generated information... // foreach (System.Web.Services.Description.ServiceDescription wsdlServiceDescription in importer.WsdlDocuments) { foreach (System.Web.Services.Description.Service wsdlService in wsdlServiceDescription.Services) { foreach (System.Web.Services.Description.Port servicePort in wsdlService.Ports) { try { ServiceEndpoint newEndpoint = importer.ImportEndpoint(servicePort); serviceEndpointList.Add(newEndpoint); } catch (InvalidOperationException) { // Invalid operation exceptions should already be in the errors collection for the importer, so we don't // need to add another generationError. The most probable cause for this is that the we failed to import // the endpoint... } catch (Exception ex) { // It is bad, because WsdlImporter.WsdlImportException is a private class generationErrors.Add(new ProxyGenerationError(ProxyGenerationError.GeneratorState.GenerateCode, wsdlServiceDescription.RetrievalUrl, ex)); } } } } bindingCollection = importer.ImportAllBindings(); System.Diagnostics.Debug.Assert(bindingCollection != null, "The importer should never return a NULL binding collection!"); contractCollection = importer.ImportAllContracts(); System.Diagnostics.Debug.Assert(contractCollection != null, "The importer should never return a NULL contract collection!"); foreach (MetadataConversionError error in importer.Errors) { generationErrors.Add(new ProxyGenerationError(error)); } } /// /// This function patches ServiceContractAttribute in the generated proxy code. It replaces all proxyNamespace in the attribute /// to configNamespace. The configNamespace does not depend on defaultNamespace of the project. /// /// /// ////// private static void PatchConfigurationNameInServiceContractAttribute(CodeCompileUnit proxyCodeUnit, string proxyNamespace, string configNamespace) { if (proxyNamespace == null) { proxyNamespace = String.Empty; } string proxyNamespaceHead = MakePeriodTerminatedNamespacePrefix(proxyNamespace); string configNamespaceHead = MakePeriodTerminatedNamespacePrefix(configNamespace); if (proxyCodeUnit != null) { foreach (CodeNamespace proxyCodeNamespace in proxyCodeUnit.Namespaces) { // Find the namespace we are patching... if (String.Equals(proxyNamespace, proxyCodeNamespace.Name, StringComparison.Ordinal)) { // ...and all types in each namespace... foreach (CodeTypeDeclaration typeDeclaration in proxyCodeNamespace.Types) { if (typeDeclaration.IsInterface) { // ...and each attribute on each interface... foreach (CodeAttributeDeclaration codeAttribute in typeDeclaration.CustomAttributes) { // find System.ServiceModel.ServiceContractAttribute attribute. if (String.Equals(codeAttribute.AttributeType.BaseType, typeof(System.ServiceModel.ServiceContractAttribute).FullName, StringComparison.Ordinal)) { foreach (CodeAttributeArgument argument in codeAttribute.Arguments) { if (String.Equals(argument.Name, "ConfigurationName", StringComparison.Ordinal)) { // we only fix the string here CodePrimitiveExpression valueExpression = argument.Value as CodePrimitiveExpression; if (valueExpression != null && valueExpression.Value is string) { valueExpression.Value = ReplaceNamespace(proxyNamespaceHead, configNamespaceHead, (string)valueExpression.Value); } } } } } } } } } } } /// /// Patch VB code for output parameters. /// /// Visual Basic doesn't support Out parameters - they are all generated as ByRef. /// Unfortunately, the CodeDom provider doesn't add an Out attribute to the ByRef /// parameters, so we have to do that ourselves... /// /// ///private static void PatchOutParametersInVB(CodeCompileUnit codeCompileUnit) { foreach (CodeNamespace codeNamespace in codeCompileUnit.Namespaces) { foreach (CodeTypeDeclaration codeClass in codeNamespace.Types) { PatchTypeDeclaration(codeClass); } } } /// /// Patch TypeDeclaration in VB code for output parameters /// /// ///private static void PatchTypeDeclaration(CodeTypeDeclaration codeClass) { foreach (CodeTypeMember member in codeClass.Members) { if (member is CodeTypeDeclaration) { // Recurse down in nested types... PatchTypeDeclaration((CodeTypeDeclaration)member); } else if (member is CodeMemberMethod) { CodeMemberMethod method = member as CodeMemberMethod; foreach (CodeParameterDeclarationExpression parameter in method.Parameters) { if (parameter.Direction == FieldDirection.Out) { // Make sure that all Out parameters have an attribute // // First check for explicit declaration to avoid adding duplicate attributes. if (!IsDefinedInCodeAttributeCollection(typeof(System.Runtime.InteropServices.OutAttribute), parameter.CustomAttributes)) { parameter.CustomAttributes.Add(OutAttribute); } } } } } } /// /// check whether code attribuate has already been declared. /// /// /// ////// private static bool IsDefinedInCodeAttributeCollection(Type type, CodeAttributeDeclarationCollection metadata) { foreach (CodeAttributeDeclaration attribute in metadata) { if (String.Equals(attribute.Name, type.FullName, StringComparison.Ordinal) || String.Equals(attribute.Name, type.Name, StringComparison.Ordinal)) { return true; } } return false; } /// /// Check whether it is VB language /// /// ////// private static bool IsVBCodeDomProvider(System.CodeDom.Compiler.CodeDomProvider codeDomProvider) { string fileExtension = codeDomProvider.FileExtension; try { string language = System.CodeDom.Compiler.CodeDomProvider.GetLanguageFromExtension(fileExtension); return String.Equals(language, VB_LANGUAGE_NAME, StringComparison.OrdinalIgnoreCase); } catch (System.Configuration.ConfigurationException) { // not defined extension return false; } } /// /// check whether HTTP Binding is used in those metadata files /// /// metadata files ////// private static bool ContainsHttpBindings(IEnumerable metadataCollection) { foreach (MetadataSection metadataSection in metadataCollection) { if (metadataSection.Dialect == MetadataSection.ServiceDescriptionDialect) { System.Web.Services.Description.ServiceDescription wsdlFile = (System.Web.Services.Description.ServiceDescription)metadataSection.Metadata; if (ContainsHttpBindings(wsdlFile)) { return true; } } } return false; } /// /// check whether HTTP Binding is used in one wsdl file /// /// one wsdl ////// internal static bool ContainsHttpBindings(System.Web.Services.Description.ServiceDescription wsdlFile) { foreach (System.Web.Services.Description.Binding binding in wsdlFile.Bindings) { foreach (object extension in binding.Extensions) { System.Web.Services.Description.HttpBinding httpBinding = extension as System.Web.Services.Description.HttpBinding; if (httpBinding != null) { return true; } } } return false; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- RuntimeEnvironment.cs
- ExpandCollapseProviderWrapper.cs
- CopyOnWriteList.cs
- CompositeActivityDesigner.cs
- MetabaseSettingsIis7.cs
- MachineKeySection.cs
- EventlogProvider.cs
- ModelItemDictionary.cs
- ProfileSettings.cs
- FrameSecurityDescriptor.cs
- Item.cs
- ByteAnimation.cs
- XPathSelectionIterator.cs
- XmlSchemaChoice.cs
- DataBinder.cs
- TrackingWorkflowEventArgs.cs
- WrappedIUnknown.cs
- ExpandSegment.cs
- Type.cs
- ProviderException.cs
- DbConnectionPoolCounters.cs
- CopyNamespacesAction.cs
- util.cs
- HyperLinkField.cs
- LogicalExpressionTypeConverter.cs
- TransformGroup.cs
- PresentationTraceSources.cs
- FixedSOMFixedBlock.cs
- NodeLabelEditEvent.cs
- SqlTypeConverter.cs
- DesignBindingValueUIHandler.cs
- XmlSchemaAnyAttribute.cs
- TreeNodeBindingCollection.cs
- HTTPNotFoundHandler.cs
- DocumentReference.cs
- AssemblyHash.cs
- UInt16Converter.cs
- RecognizerInfo.cs
- FillErrorEventArgs.cs
- OracleConnectionFactory.cs
- GenericTextProperties.cs
- ResourceContainer.cs
- ReachPrintTicketSerializer.cs
- UidManager.cs
- TextInfo.cs
- XmlSchemaSimpleContent.cs
- RemotingServices.cs
- XsltQilFactory.cs
- __Error.cs
- StrongName.cs
- MD5.cs
- DelegatingConfigHost.cs
- DesignerToolStripControlHost.cs
- DBCommand.cs
- TaskHelper.cs
- ContextDataSourceView.cs
- AsyncPostBackTrigger.cs
- _NestedMultipleAsyncResult.cs
- PageCache.cs
- ParameterBuilder.cs
- CodeThrowExceptionStatement.cs
- KnownTypesProvider.cs
- TransformedBitmap.cs
- TraceProvider.cs
- ConstantProjectedSlot.cs
- DuplexChannelBinder.cs
- PeerDuplexChannel.cs
- ImageMap.cs
- GradientStop.cs
- PhoneCall.cs
- Error.cs
- AppDomainResourcePerfCounters.cs
- AutoGeneratedFieldProperties.cs
- AssemblyBuilder.cs
- ServicePoint.cs
- ItemsControlAutomationPeer.cs
- mda.cs
- ValueOfAction.cs
- CodeTypeDelegate.cs
- ValueQuery.cs
- ChannelBinding.cs
- Token.cs
- XmlReaderSettings.cs
- IdentitySection.cs
- ByteConverter.cs
- ProxyWebPartManager.cs
- WebBrowserNavigatingEventHandler.cs
- FunctionMappingTranslator.cs
- FrameworkRichTextComposition.cs
- CompositeActivityDesigner.cs
- NetworkCredential.cs
- TextEndOfParagraph.cs
- HandlerFactoryCache.cs
- ExtenderProvidedPropertyAttribute.cs
- DBSchemaRow.cs
- UriWriter.cs
- UnmanagedMemoryStream.cs
- SiteMembershipCondition.cs
- PopOutPanel.cs
- PageVisual.cs