/// <summary> /// Create an appropriate XsdDataContractImporter for the generator /// </summary> /// <param name="proxyOptions">Code/config generation options to use</param> /// <param name="targetCompileUnit">CodeCompileUnit into which we will generate the client code</param> /// <param name="codeDomProvider">CodeDomProvider for the language we will use to generate the client</param> /// <param name="proxyNamespace">CLR namespace in which the client code will be generated</param> /// <param name="typeLoader">Service used to resolve type/assembly names (strings) to actual Types and Assemblies</param> /// <param name="targetFrameworkVersion">Targetted Framework version number</param> /// <param name="importErrors">List of errors encountered. New errors will be added to this list</param> /// <returns></returns> protected static XsdDataContractImporter CreateDataContractImporter( ClientOptions proxyOptions, CodeCompileUnit targetCompileUnit, System.CodeDom.Compiler.CodeDomProvider codeDomProvider, string proxyNamespace, IContractGeneratorReferenceTypeLoader typeLoader, int targetFrameworkVersion, IList<ProxyGenerationError> 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<Type> referencedTypes = LoadSharedDataContractTypes(proxyOptions, typeLoader, targetFrameworkVersion, importErrors); if (referencedTypes != null) { foreach (Type sharedType in referencedTypes) { options.ReferencedTypes.Add(sharedType); } } IEnumerable<Type> 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; }
protected static IEnumerable<Type> LoadSharedDataContractTypes( ClientOptions proxyOptions, IContractGeneratorReferenceTypeLoader typeLoader, int targetFrameworkVersion, IList<ProxyGenerationError> 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<Type, ReferencedType> sharedTypeTable = new Dictionary<Type, ReferencedType>(); // load all types in referencedAssemblies IEnumerable<Assembly> referencedAssemblies = LoadReferenedAssemblies(proxyOptions, typeLoader, importErrors); if (referencedAssemblies != null) { foreach (Assembly referencedAssembly in referencedAssemblies) { var typeLoader2 = typeLoader as IContractGeneratorReferenceTypeLoader2; if (typeLoader2 != null) { foreach (Type sharedType in typeLoader2.LoadExportedTypes(referencedAssembly)) { sharedTypeTable.Add(sharedType, null); } } else { // Fall back to the original approach using IContractGeneratorReferenceTypeLoader.LoadType(). foreach (Type typeInAssembly in referencedAssembly.GetExportedTypes()) { try { // Do multi-targeting check by calling IContractGeneratorReferenceTypeLoader.LoadType(). if (typeLoader.LoadType(typeInAssembly.FullName) != null) { sharedTypeTable.Add(typeInAssembly, null); } } catch (NotSupportedException) { // NotSupportedException is thrown by multi-targeting check. It's normal if some types not existing in the current FX. // So we can safely ---- it. } 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; }
/// <summary> /// Instantiate and configure a ServiceContractGenerator to be used for code and config /// generation. /// </summary> /// <param name="proxyOptions"> /// Options set in the SvcMap file to control the code/config generation. /// </param> /// <param name="wsdlImporter"> /// The WsdlImporter that is to be used to import the metadata for this service reference. /// </param> /// <param name="targetCompileUnit"> /// Compile unit into which we will generate the client code /// </param> /// <param name="proxyNamespace"> /// The CLR namespace into which we will generate the client code. /// </param> /// <param name="targetConfiguration"> /// 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. /// </param> /// <param name="typeLoader"> /// Type loader that can be used to find reference assemblies and/or resolve shared service and /// data contract types. /// </param> /// <param name="targetFrameworkVersion"> /// The target framework version number. The higher 16 bits contains the major version number, and low 16 bits contains minor version number. /// </param> /// <param name="importErrors"> /// The list into which we will add any errors while importing the metadata. /// </param> /// <returns></returns> protected static ServiceContractGenerator CreateContractGenerator(ClientOptions proxyOptions, WsdlImporter wsdlImporter, CodeCompileUnit targetCompileUnit, string proxyNamespace, System.Configuration.Configuration targetConfiguration, IContractGeneratorReferenceTypeLoader typeLoader, int targetFrameworkVersion, IList<ProxyGenerationError> 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; } // Make sure at most one of the async options will be set: AsynchronousMethods | TaskBasedAsynchronousMethod. contractGenerator.Options &= ~ServiceContractGenerationOptions.AsynchronousMethods & ~ServiceContractGenerationOptions.EventBasedAsynchronousMethods & ~ServiceContractGenerationOptions.TaskBasedAsynchronousMethod; if (proxyOptions.GenerateTaskBasedAsynchronousMethod) { contractGenerator.Options |= ServiceContractGenerationOptions.TaskBasedAsynchronousMethod; } else if (proxyOptions.GenerateAsynchronousMethods) { contractGenerator.Options |= ServiceContractGenerationOptions.AsynchronousMethods; if (targetFrameworkVersion >= FRAMEWORK_VERSION_35) { contractGenerator.Options |= ServiceContractGenerationOptions.EventBasedAsynchronousMethods; } } 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; }
/// <summary> /// Factory method: generate code and return the resulting VSWCFServiceContractGenerator. /// </summary> /// <param name="svcMapFile"> /// The SvcMapFile that lists the metadata and generation options for the service reference. /// </param> /// <param name="toolConfiguration"> /// 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. /// </param> /// <param name="codeDomProvider"> /// CodeDom provider that is to be used to generate the client code. /// </param> /// <param name="proxyNamespace"> /// CLR namespace in which to generate the client code. /// </param> /// <param name="targetConfiguration"> /// The configuration into which we will put bindings/endpoints for this service /// reference. May be Null/Nothing. /// </param> /// <param name="configurationNamespace"> /// The namespace that is to be used in configuration for this service reference. /// </param> /// <param name="serviceProviderForImportExtensions"> /// Service provider that we'll pass on to import extensions that accept our site:ing /// mechanism /// </param> /// <param name="typeLoader"> /// Type loader that can be used to find reference assemblies and/or resolve shared service and /// data contract types. /// </param> /// <param name="targetFrameworkVersion"> /// The target framework version number. The higher 16 bits contains the major version number, and low 16 bits contains minor version number. /// </param> /// <param name="typedDataSetSchemaImporterExtension"> /// Schema importer extension to be used for typed datasets. /// </param> /// <returns> /// A VSWCFServiceContractGenerator instance that contains the result of the generation. To get /// hold of the generated information, you can query it's properties. /// </returns> 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"); List<ProxyGenerationError> importErrors = new List<ProxyGenerationError>(); List<ProxyGenerationError> proxyGenerationErrors = new List<ProxyGenerationError>(); 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<ServiceEndpoint> serviceEndpointList = new List<ServiceEndpoint>(); IEnumerable<System.ServiceModel.Channels.Binding> bindingCollection; IEnumerable<ContractDescription> contractCollection; ImportWCFModel(wsdlImporter, targetCompileUnit, importErrors, out serviceEndpointList, out bindingCollection, out contractCollection); Dictionary<ServiceEndpoint, ChannelEndpointElement> serviceEndpointToChannelEndpointElementMap; List<GeneratedContractType> proxyGeneratedContractTypes; GenerateProxy(wsdlImporter, 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 proxyGenerationErrors.Add(new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, ex, false)); return new VSWCFServiceContractGenerator(importErrors, new CodeCompileUnit(), targetConfiguration, new List<System.ServiceModel.Channels.Binding>(), new List<ContractDescription>(), new List<ServiceEndpoint>(), new Dictionary<ServiceEndpoint, ChannelEndpointElement>(), new List<GeneratedContractType>(), proxyGenerationErrors); } }
/// <summary> /// Create an appropriate WsdlImporter for the generator /// </summary> /// <param name="svcMapFile"></param> /// <param name="toolConfiguration"></param> /// <param name="targetCompileUnit"></param> /// <param name="codeDomProvider"></param> /// <param name="targetNamespace"></param> /// <param name="typeLoader"></param> /// <param name="targetFrameworkVersion">Targetted Framework version number</param> /// <param name="importErrors"></param> /// <param name="typedDataSetSchemaImporterExtension"></param> /// <returns></returns> 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<ProxyGenerationError> importErrors, System.Type typedDataSetSchemaImporterExtension) { List<MetadataSection> 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 serializerType = ClientOptions.ProxySerializerType.XmlSerializer; } if (toolConfiguration != null) { ServiceModelSectionGroup serviceModelSection = ServiceModelSectionGroup.GetSectionGroup(toolConfiguration); if (serviceModelSection != null) { Collection<IWsdlImportExtension> wsdlImportExtensions = serviceModelSection.Client.Metadata.LoadWsdlImportExtensions(); Collection<IPolicyImportExtension> 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); wsdlImportExtensions.Add(new HttpBindingExtension()); // 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; }
/// <summary> /// 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. /// </summary> /// <param name="proxyOptions">Options specifying the list of collection types</param> /// <param name="typeLoader">Type loader that resolves type names to actual CLR types</param> /// <param name="importErrors">Errors encountered while loading the collection types</param> /// <return></return> /// <remarks></remarks> protected static IEnumerable<Type> LoadSharedCollectionTypes(ClientOptions proxyOptions, IContractGeneratorReferenceTypeLoader typeLoader, IList<ProxyGenerationError> importErrors) { List<Type> referencedCollectionTypes = new List<Type>(); 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; }
/// <summary> /// Load referenced assemblies /// </summary> /// <param name="proxyOptions"></param> /// <param name="typeLoader"></param> /// <param name="importErrors"></param> /// <return></return> /// <remarks></remarks> private static IEnumerable<Assembly> LoadReferenedAssemblies(ClientOptions proxyOptions, IContractGeneratorReferenceTypeLoader typeLoader, IList<ProxyGenerationError> importErrors) { List<Assembly> referencedAssemblies = new List<Assembly>(); if (proxyOptions.ReferenceAllAssemblies) { try { IEnumerable<Exception> loadingErrors = null; IEnumerable<Assembly> 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; }