1 #region Copyright (c) Microsoft Corporation
2 /// <copyright company='Microsoft Corporation'>
3 /// Copyright (c) Microsoft Corporation. All Rights Reserved.
4 /// Information Contained Herein is Proprietary and Confidential.
9 using System.Collections.Generic;
10 using System.Collections.ObjectModel;
11 using System.Globalization;
12 using System.Reflection;
13 using System.Runtime.Serialization;
14 using System.ServiceModel;
15 using System.ServiceModel.Channels;
16 using System.ServiceModel.Configuration;
17 using System.ServiceModel.Description;
19 using System.Xml.Schema;
20 using System.Security.Permissions;
23 #if WEB_EXTENSIONS_CODE
24 using System.Security;
25 using System.Web.Resources;
27 using Microsoft.VSDesigner.WCF.Resources;
31 /// The VSWCFServiceContractGenerator takes a SvcMap file and it's associated metadata,
32 /// imports the metadata using a WsdlImporter and System.ServiceModel.ServiceContractGenerator
33 /// that are configured according to the options set in the SvcMap file
35 using Debug = System.Diagnostics.Debug;
36 using System.Diagnostics.CodeAnalysis;
38 #if WEB_EXTENSIONS_CODE
39 namespace System.Web.Compilation.WCFModel
41 namespace Microsoft.VSDesigner.WCFModel
45 /// Proxy and configuration generator
47 #if WEB_EXTENSIONS_CODE
48 [PermissionSet(SecurityAction.InheritanceDemand, Name="FullTrust")]
50 internal class VSWCFServiceContractGenerator
52 // We only check for CLS compliant for the public version of this class since the
53 // compiler will complain about CLS compliance not being checked for non-public classes
55 [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
56 [PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")]
57 public class VSWCFServiceContractGenerator
61 #region Private backing fields
62 private const string VB_LANGUAGE_NAME = "vb";
65 /// Collection to hold all bindings generated by this generator
67 private IEnumerable<System.ServiceModel.Channels.Binding> bindingCollection;
70 /// Collection to hold all contracts generated by this generator
72 private IEnumerable<ContractDescription> contractCollection;
75 /// Collection to hold all endpoints generated by this generator
77 private List<ServiceEndpoint> serviceEndpointList;
80 /// Map from service endpoint to the channel endpoint that was actually imported
82 private Dictionary<ServiceEndpoint, ChannelEndpointElement> serviceEndpointToChannelEndpointElementMap;
85 /// List of contract types generate by this generator
87 private List<GeneratedContractType> proxyGeneratedContractTypes;
90 /// The target compile unit that contains the proxy and data contracts
92 private CodeCompileUnit targetCompileUnit;
95 /// Configuration object that we inserterd bindings and endpoints from the
96 /// current service into. May be Null/Nothing.
98 private System.Configuration.Configuration targetConfiguration;
101 /// Errors encountered while generating the proxy
103 private IEnumerable<ProxyGenerationError> proxyGenerationErrors;
106 /// Errors encountered while importing the metadata..
108 private IList<ProxyGenerationError> importErrors;
111 /// Helper property that is added to Out parameters for VB
113 private static CodeAttributeDeclaration outAttribute;
116 /// version number for 3.5 framework
118 private const int FRAMEWORK_VERSION_35 = 0x30005;
121 /// list of types which are new in the 3.5 framework.
123 private static Type[] unsupportedTypesInFramework30 = new Type[] {
124 typeof(DateTimeOffset),
130 #region Public read-only properties
133 /// The collection of bindings generated by this generator
138 public IEnumerable<System.ServiceModel.Channels.Binding> BindingCollection
142 System.Diagnostics.Debug.Assert(bindingCollection != null);
143 return bindingCollection;
148 /// The collection of generated contract types
150 public IEnumerable<GeneratedContractType> ProxyGeneratedContractTypes
154 System.Diagnostics.Debug.Assert(proxyGeneratedContractTypes != null);
155 return proxyGeneratedContractTypes;
160 /// The collection of errors encountered while generating the
161 /// proxy. For errors related to the metadata import, use the
162 /// ImportErrors property
164 public IEnumerable<ProxyGenerationError> ProxyGenerationErrors
168 System.Diagnostics.Debug.Assert(proxyGenerationErrors != null);
169 return proxyGenerationErrors;
174 /// The collection of errors encountered while importing metadata.
175 /// For errors related to the proxy and config generation, use the
176 /// ProxyGenerationErrors property
178 public IEnumerable<ProxyGenerationError> ImportErrors
182 System.Diagnostics.Debug.Assert(importErrors != null);
188 /// The collection of contracts imported by this generator
191 /// <remarks></remarks>
192 public IEnumerable<ContractDescription> ContractCollection
196 System.Diagnostics.Debug.Assert(contractCollection != null);
197 return contractCollection;
202 /// Collection of Endpoints in the service model generated by
206 /// <remarks></remarks>
207 public IEnumerable<ServiceEndpoint> EndpointCollection
211 System.Diagnostics.Debug.Assert(serviceEndpointList != null);
212 return serviceEndpointList;
217 /// Map from service endpoints to its corresponding channel endpoint configuration
220 public Dictionary<ServiceEndpoint, ChannelEndpointElement> EndpointMap
224 System.Diagnostics.Debug.Assert(serviceEndpointToChannelEndpointElementMap != null);
225 return serviceEndpointToChannelEndpointElementMap;
230 /// The configuratin into which we inject the bindings and endpoints. May be null/Nothing
231 /// if no target configuration was provided.
233 public System.Configuration.Configuration TargetConfiguration
237 // Note: it is valid for this to be NULL. Caller beware!
238 return targetConfiguration;
243 /// CodeCompileUnit containing the generated data contracts, service contracts
246 public CodeCompileUnit TargetCompileUnit
250 System.Diagnostics.Debug.Assert(targetCompileUnit != null);
251 return targetCompileUnit;
258 /// Cached instance of an Out attribute that we use to patch up
259 /// the codegen for VB projects (the VB code generates out parameters
262 private static CodeAttributeDeclaration OutAttribute
266 if (outAttribute == null)
268 outAttribute = new CodeAttributeDeclaration(typeof(System.Runtime.InteropServices.OutAttribute).FullName);
275 /// protected constructor to block creating instance directly.
277 /// <param name="importErrors"></param>
278 /// <param name="targetCompileUnit"></param>
279 /// <param name="targetConfiguration">May be null</param>
280 /// <param name="bindingCollection"></param>
281 /// <param name="contractCollection"></param>
282 /// <param name="serviceEndpointList"></param>
283 /// <param name="serviceEndpointToChannelEndpointElementMap"></param>
284 /// <param name="proxyGeneratedContractTypes"></param>
285 /// <param name="proxyGenerationErrors"></param>
286 protected VSWCFServiceContractGenerator(
287 List<ProxyGenerationError> importErrors,
288 CodeCompileUnit targetCompileUnit,
289 System.Configuration.Configuration targetConfiguration,
290 IEnumerable<System.ServiceModel.Channels.Binding> bindingCollection,
291 IEnumerable<ContractDescription> contractCollection,
292 List<ServiceEndpoint> serviceEndpointList,
293 Dictionary<ServiceEndpoint, ChannelEndpointElement> serviceEndpointToChannelEndpointElementMap,
294 List<GeneratedContractType> proxyGeneratedContractTypes,
295 IEnumerable<ProxyGenerationError> proxyGenerationErrors)
297 if (importErrors == null) throw new ArgumentNullException("importErrors");
298 if (targetCompileUnit == null) throw new ArgumentNullException("targetCompileUnit");
299 // Please note - target configuration may be NULL
300 if (bindingCollection == null) throw new ArgumentNullException("bindingCollection");
301 if (contractCollection == null) throw new ArgumentNullException("contractCollection");
302 if (serviceEndpointList == null) throw new ArgumentNullException("serviceEndpointList");
303 if (serviceEndpointToChannelEndpointElementMap == null) throw new ArgumentNullException("serviceEndpointToChannelEndpointElementMap");
304 if (proxyGeneratedContractTypes == null) throw new ArgumentNullException("proxyGeneratedContractTypes");
305 if (proxyGenerationErrors == null) throw new ArgumentNullException("proxyGenerationErrors");
307 this.importErrors = importErrors;
308 this.targetCompileUnit = targetCompileUnit;
309 this.targetConfiguration = targetConfiguration;
310 this.bindingCollection = bindingCollection;
311 this.contractCollection = contractCollection;
312 this.serviceEndpointList = serviceEndpointList;
313 this.serviceEndpointToChannelEndpointElementMap = serviceEndpointToChannelEndpointElementMap;
314 this.proxyGeneratedContractTypes = proxyGeneratedContractTypes;
315 this.proxyGenerationErrors = proxyGenerationErrors;
319 /// Factory method: generate code and return the resulting VSWCFServiceContractGenerator.
321 /// <param name="svcMapFile">
322 /// The SvcMapFile that lists the metadata and generation options for the service reference.
324 /// <param name="toolConfiguration">
325 /// Configuration from which we are going to pick up WSDL and policy importer extensions as well
326 /// as custom MEX bindings for metadata download. May be Null/Nothing.
328 /// <param name="codeDomProvider">
329 /// CodeDom provider that is to be used to generate the client code.
331 /// <param name="proxyNamespace">
332 /// CLR namespace in which to generate the client code.
334 /// <param name="targetConfiguration">
335 /// The configuration into which we will put bindings/endpoints for this service
336 /// reference. May be Null/Nothing.
338 /// <param name="configurationNamespace">
339 /// The namespace that is to be used in configuration for this service reference.
341 /// <param name="serviceProviderForImportExtensions">
342 /// Service provider that we'll pass on to import extensions that accept our site:ing
345 /// <param name="typeLoader">
346 /// Type loader that can be used to find reference assemblies and/or resolve shared service and
347 /// data contract types.
349 /// <param name="targetFrameworkVersion">
350 /// The target framework version number. The higher 16 bits contains the major version number, and low 16 bits contains minor version number.
352 /// <param name="typedDataSetSchemaImporterExtension">
353 /// Schema importer extension to be used for typed datasets.
356 /// A VSWCFServiceContractGenerator instance that contains the result of the generation. To get
357 /// hold of the generated information, you can query it's properties.
359 public static VSWCFServiceContractGenerator GenerateCodeAndConfiguration(SvcMapFile svcMapFile,
360 System.Configuration.Configuration toolConfiguration,
361 System.CodeDom.Compiler.CodeDomProvider codeDomProvider,
362 string proxyNamespace,
363 System.Configuration.Configuration targetConfiguration,
364 string configurationNamespace,
365 IServiceProvider serviceProviderForImportExtensions,
366 IContractGeneratorReferenceTypeLoader typeLoader,
367 int targetFrameworkVersion,
368 System.Type typedDataSetSchemaImporterExtension)
370 if (svcMapFile == null) throw new ArgumentNullException("svcMapFile");
371 if (codeDomProvider == null) throw new ArgumentNullException("codeDomProvider");
372 if (typedDataSetSchemaImporterExtension == null) throw new ArgumentNullException("typedDataSetSchemaImporterExtension");
374 List<ProxyGenerationError> importErrors = new List<ProxyGenerationError>();
375 List<ProxyGenerationError> proxyGenerationErrors = new List<ProxyGenerationError>();
377 CodeCompileUnit targetCompileUnit = new CodeCompileUnit();
379 WsdlImporter wsdlImporter = CreateWsdlImporter(svcMapFile,
384 serviceProviderForImportExtensions,
386 targetFrameworkVersion,
388 typedDataSetSchemaImporterExtension);
390 ServiceContractGenerator contractGenerator = CreateContractGenerator(svcMapFile.ClientOptions,
396 targetFrameworkVersion,
401 List<ServiceEndpoint> serviceEndpointList = new List<ServiceEndpoint>();
402 IEnumerable<System.ServiceModel.Channels.Binding> bindingCollection;
403 IEnumerable<ContractDescription> contractCollection;
405 ImportWCFModel(wsdlImporter,
408 out serviceEndpointList,
409 out bindingCollection,
410 out contractCollection);
412 Dictionary<ServiceEndpoint, ChannelEndpointElement> serviceEndpointToChannelEndpointElementMap;
413 List<GeneratedContractType> proxyGeneratedContractTypes;
415 GenerateProxy(wsdlImporter,
419 configurationNamespace,
423 proxyGenerationErrors,
424 out serviceEndpointToChannelEndpointElementMap,
425 out proxyGeneratedContractTypes);
427 if (IsVBCodeDomProvider(codeDomProvider))
429 PatchOutParametersInVB(targetCompileUnit);
432 return new VSWCFServiceContractGenerator(importErrors,
438 serviceEndpointToChannelEndpointElementMap,
439 proxyGeneratedContractTypes,
440 proxyGenerationErrors);
444 // fatal error... (workaround for bug #135242)
445 // We want to convert fatal error exception to a normal code generator error message,
446 // so the user could find information from pervious errors to find KB topic.
447 proxyGenerationErrors.Add(new ProxyGenerationError(
448 ProxyGenerationError.GeneratorState.GenerateCode,
453 return new VSWCFServiceContractGenerator(importErrors,
454 new CodeCompileUnit(),
456 new List<System.ServiceModel.Channels.Binding>(),
457 new List<ContractDescription>(),
458 new List<ServiceEndpoint>(),
459 new Dictionary<ServiceEndpoint, ChannelEndpointElement>(),
460 new List<GeneratedContractType>(),
461 proxyGenerationErrors);
468 /// Instantiate and configure a ServiceContractGenerator to be used for code and config
471 /// <param name="proxyOptions">
472 /// Options set in the SvcMap file to control the code/config generation.
474 /// <param name="wsdlImporter">
475 /// The WsdlImporter that is to be used to import the metadata for this service reference.
477 /// <param name="targetCompileUnit">
478 /// Compile unit into which we will generate the client code
480 /// <param name="proxyNamespace">
481 /// The CLR namespace into which we will generate the client code.
483 /// <param name="targetConfiguration">
484 /// Optional configuration into which we will generate the endpoints/bindings corresponding
485 /// to this service reference. May be Null/Nothing, in which case we will not generate config.
487 /// <param name="typeLoader">
488 /// Type loader that can be used to find reference assemblies and/or resolve shared service and
489 /// data contract types.
491 /// <param name="targetFrameworkVersion">
492 /// The target framework version number. The higher 16 bits contains the major version number, and low 16 bits contains minor version number.
494 /// <param name="importErrors">
495 /// The list into which we will add any errors while importing the metadata.
497 /// <returns></returns>
498 protected static ServiceContractGenerator CreateContractGenerator(ClientOptions proxyOptions,
499 WsdlImporter wsdlImporter,
500 CodeCompileUnit targetCompileUnit,
501 string proxyNamespace,
502 System.Configuration.Configuration targetConfiguration,
503 IContractGeneratorReferenceTypeLoader typeLoader,
504 int targetFrameworkVersion,
505 IList<ProxyGenerationError> importErrors)
507 ServiceContractGenerator contractGenerator = new ServiceContractGenerator(targetCompileUnit, targetConfiguration);
509 // We want to generate all types into the proxy namespace CLR namespace. We indicate
510 // this by adding a namespace mapping from all XML namespaces ("*") to the namespace
511 // the caller told us to generate the client code in.
512 contractGenerator.NamespaceMappings.Add("*", proxyNamespace);
514 if (proxyOptions.GenerateInternalTypes)
516 contractGenerator.Options |= ServiceContractGenerationOptions.InternalTypes;
520 contractGenerator.Options &= ~ServiceContractGenerationOptions.InternalTypes;
523 // Make sure at most one of the async options will be set: AsynchronousMethods | TaskBasedAsynchronousMethod.
524 contractGenerator.Options &= ~ServiceContractGenerationOptions.AsynchronousMethods &
525 ~ServiceContractGenerationOptions.EventBasedAsynchronousMethods &
526 ~ServiceContractGenerationOptions.TaskBasedAsynchronousMethod;
528 if (proxyOptions.GenerateTaskBasedAsynchronousMethod)
530 contractGenerator.Options |= ServiceContractGenerationOptions.TaskBasedAsynchronousMethod;
532 else if (proxyOptions.GenerateAsynchronousMethods)
534 contractGenerator.Options |= ServiceContractGenerationOptions.AsynchronousMethods;
535 if (targetFrameworkVersion >= FRAMEWORK_VERSION_35)
537 contractGenerator.Options |= ServiceContractGenerationOptions.EventBasedAsynchronousMethods;
541 if (proxyOptions.GenerateMessageContracts)
543 contractGenerator.Options |= ServiceContractGenerationOptions.TypedMessages;
547 contractGenerator.Options &= ~ServiceContractGenerationOptions.TypedMessages;
550 // If we have a type loader, we tell the contract generator and wsdl importer about
551 // all shared types and assemblies that we've specified in the proxy options...
552 if (typeLoader != null)
554 foreach (ContractMapping mapping in proxyOptions.ServiceContractMappingList)
558 Type sharedType = typeLoader.LoadType(mapping.TypeName);
560 // verify that the type is shareable - if not, we generate an error...
561 if (!IsTypeShareable(sharedType))
564 new ProxyGenerationError(
565 ProxyGenerationError.GeneratorState.GenerateCode,
567 new FormatException(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_SharedTypeMustBePublic, mapping.TypeName)))
572 // Get a contract description corresponding to the type we wanted to share
573 ContractDescription contract = ContractDescription.GetContract(sharedType);
575 if (!String.Equals(mapping.Name, contract.Name, StringComparison.Ordinal) ||
576 !String.Equals(mapping.TargetNamespace, contract.Namespace, StringComparison.Ordinal))
580 new ProxyGenerationError(
581 ProxyGenerationError.GeneratorState.GenerateCode,
583 new FormatException(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_ServiceContractMappingMissMatch, mapping.TypeName, contract.Namespace, contract.Name, mapping.TargetNamespace, mapping.Name)))
587 XmlQualifiedName qname = new XmlQualifiedName(contract.Name, contract.Namespace);
588 wsdlImporter.KnownContracts.Add(qname, contract);
589 contractGenerator.ReferencedTypes.Add(contract, sharedType);
593 importErrors.Add(new ProxyGenerationError(
594 ProxyGenerationError.GeneratorState.GenerateCode,
601 foreach (NamespaceMapping namespaceMapping in proxyOptions.NamespaceMappingList)
603 contractGenerator.NamespaceMappings.Add(namespaceMapping.TargetNamespace, namespaceMapping.ClrNamespace);
606 return contractGenerator;
610 /// Generate Proxy Code and (if available) configuration
612 /// <param name="contractGenerator">The contract generator to use</param>
613 /// <param name="targetCompileUnit">Compile unit into which we should generate the client code</param>
614 /// <param name="proxyNamespace">CLR namespace into which we should generate the client code</param>
615 /// <param name="configurationNamespace">Namespace to use in configuration</param>
616 /// <param name="contractCollection">The contracts for which we should generate code and optionally config</param>
617 /// <param name="bindingCollection">The bindings we should generate config for</param>
618 /// <param name="serviceEndpointList">The endpoints we should generate config for</param>
619 /// <param name="proxyGenerationErrors">A list of errors encountered while generating the client</param>
620 /// <param name="serviceEndpointToChannelEndpointElementMap">Map from service endpoint to the configuration element for the endpoint</param>
621 /// <param name="proxyGeneratedContractTypes">The generated contract types</param>
622 protected static void GenerateProxy(WsdlImporter importer,
623 ServiceContractGenerator contractGenerator,
624 CodeCompileUnit targetCompileUnit,
625 string proxyNamespace,
626 string configurationNamespace,
627 IEnumerable<ContractDescription> contractCollection,
628 IEnumerable<System.ServiceModel.Channels.Binding> bindingCollection,
629 List<ServiceEndpoint> serviceEndpointList,
630 IList<ProxyGenerationError> proxyGenerationErrors,
631 out Dictionary<ServiceEndpoint, ChannelEndpointElement> serviceEndpointToChannelEndpointElementMap,
632 out List<GeneratedContractType> proxyGeneratedContractTypes)
634 // Parameter checking
635 if (serviceEndpointList == null) throw new ArgumentNullException("serviceEndpointList");
636 if (bindingCollection == null) throw new ArgumentNullException("bindingCollection");
637 if (contractCollection == null) throw new ArgumentNullException("contractCollection");
638 if (proxyGenerationErrors == null) throw new ArgumentNullException("proxyGenerationErrors");
640 proxyGeneratedContractTypes = new List<GeneratedContractType>();
641 serviceEndpointToChannelEndpointElementMap = new Dictionary<ServiceEndpoint, ChannelEndpointElement>();
645 HttpBindingExtension httpBindingEx = importer.WsdlImportExtensions.Find<HttpBindingExtension>();
647 foreach (ContractDescription contract in contractCollection)
649 if (httpBindingEx == null || !httpBindingEx.IsHttpBindingContract(contract) || serviceEndpointList.Any(endpoint => endpoint.Contract == contract))
651 CodeTypeReference typeReference = contractGenerator.GenerateServiceContractType(contract);
652 if (typeReference != null)
654 // keep the (targetNamespace, portType) -> CLR type map table...
656 string baseType = typeReference.BaseType;
658 GeneratedContractType generatedType = new GeneratedContractType(contract.Namespace, contract.Name, baseType, baseType);
659 proxyGeneratedContractTypes.Add(generatedType);
664 // We should only import the Binding & Endpoints if there is a configuration storage...
665 if (contractGenerator.Configuration != null)
667 foreach (ServiceEndpoint endpoint in serviceEndpointList)
669 ChannelEndpointElement endpointElement = null;
670 contractGenerator.GenerateServiceEndpoint(endpoint, out endpointElement);
671 serviceEndpointToChannelEndpointElementMap[endpoint] = endpointElement;
674 foreach (System.ServiceModel.Channels.Binding bindingDescription in bindingCollection)
676 string bindingSectionName = null;
677 string bindingConfigurationName = null;
678 // Generate binding will change the state of the contractGenerator...
679 contractGenerator.GenerateBinding(bindingDescription, out bindingSectionName, out bindingConfigurationName);
684 PatchConfigurationName(proxyNamespace,
685 configurationNamespace,
686 proxyGeneratedContractTypes,
687 serviceEndpointToChannelEndpointElementMap.Values,
692 foreach (MetadataConversionError error in contractGenerator.Errors)
694 proxyGenerationErrors.Add(new ProxyGenerationError(error));
700 /// Create appropriate XmlSerializerImportOptions for the generator
702 /// <param name="proxyOptions">Options for the code/config generation</param>
703 /// <param name="targetCompileUnit">Compile unit we are going to generate the client code in</param>
704 /// <param name="codeDomProvider">CodeDom provider for the language we are using</param>
705 /// <param name="proxyNamespace">CLR namespace we'll put the client code in</param>
706 /// <returns></returns>
707 protected static XmlSerializerImportOptions CreateXmlSerializerImportOptions(
708 ClientOptions proxyOptions,
709 CodeCompileUnit targetCompileUnit,
710 System.CodeDom.Compiler.CodeDomProvider codeDomProvider,
711 string proxyNamespace,
712 System.Type typedDataSetSchemaImporterExtension)
714 System.ServiceModel.Channels.XmlSerializerImportOptions xmlSerializerOptions = new XmlSerializerImportOptions(targetCompileUnit);
715 System.Web.Services.Description.WebReferenceOptions webReferenceOptions = new System.Web.Services.Description.WebReferenceOptions();
717 webReferenceOptions.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateProperties | System.Xml.Serialization.CodeGenerationOptions.GenerateOrder;
719 if (proxyOptions.EnableDataBinding)
721 webReferenceOptions.CodeGenerationOptions |= System.Xml.Serialization.CodeGenerationOptions.EnableDataBinding;
724 webReferenceOptions.SchemaImporterExtensions.Add(typedDataSetSchemaImporterExtension.AssemblyQualifiedName);
725 webReferenceOptions.SchemaImporterExtensions.Add(typeof(System.Data.DataSetSchemaImporterExtension).AssemblyQualifiedName);
747 xmlSerializerOptions.WebReferenceOptions = webReferenceOptions;
748 xmlSerializerOptions.CodeProvider = codeDomProvider;
750 xmlSerializerOptions.ClrNamespace = proxyNamespace;
752 return xmlSerializerOptions;
756 /// Create an appropriate XsdDataContractImporter for the generator
758 /// <param name="proxyOptions">Code/config generation options to use</param>
759 /// <param name="targetCompileUnit">CodeCompileUnit into which we will generate the client code</param>
760 /// <param name="codeDomProvider">CodeDomProvider for the language we will use to generate the client</param>
761 /// <param name="proxyNamespace">CLR namespace in which the client code will be generated</param>
762 /// <param name="typeLoader">Service used to resolve type/assembly names (strings) to actual Types and Assemblies</param>
763 /// <param name="targetFrameworkVersion">Targetted Framework version number</param>
764 /// <param name="importErrors">List of errors encountered. New errors will be added to this list</param>
765 /// <returns></returns>
766 protected static XsdDataContractImporter CreateDataContractImporter(
767 ClientOptions proxyOptions,
768 CodeCompileUnit targetCompileUnit,
769 System.CodeDom.Compiler.CodeDomProvider codeDomProvider,
770 string proxyNamespace,
771 IContractGeneratorReferenceTypeLoader typeLoader,
772 int targetFrameworkVersion,
773 IList<ProxyGenerationError> importErrors)
775 System.Runtime.Serialization.XsdDataContractImporter xsdDataContractImporter = new System.Runtime.Serialization.XsdDataContractImporter(targetCompileUnit);
776 System.Runtime.Serialization.ImportOptions options = new System.Runtime.Serialization.ImportOptions();
778 options.CodeProvider = codeDomProvider;
780 // We specify that we want to generate all types from all XML namespaces into
781 // our proxy namespace. By default, each XML namespace get's its own CLR namespace
782 options.Namespaces.Add("*", proxyNamespace);
783 options.GenerateInternal = proxyOptions.GenerateInternalTypes;
784 options.GenerateSerializable = proxyOptions.GenerateSerializableTypes;
785 options.EnableDataBinding = proxyOptions.EnableDataBinding;
786 options.ImportXmlType = proxyOptions.ImportXmlTypes;
788 if (typeLoader != null)
790 IEnumerable<Type> referencedTypes = LoadSharedDataContractTypes(proxyOptions, typeLoader, targetFrameworkVersion, importErrors);
791 if (referencedTypes != null)
793 foreach (Type sharedType in referencedTypes)
795 options.ReferencedTypes.Add(sharedType);
799 IEnumerable<Type> referencedCollectionTypes = LoadSharedCollectionTypes(proxyOptions, typeLoader, importErrors);
800 if (referencedCollectionTypes != null)
802 foreach (Type collectionType in referencedCollectionTypes)
804 options.ReferencedCollectionTypes.Add(collectionType);
810 foreach (NamespaceMapping namespaceMapping in proxyOptions.NamespaceMappingList)
812 options.Namespaces.Add(namespaceMapping.TargetNamespace, namespaceMapping.ClrNamespace);
815 xsdDataContractImporter.Options = options;
817 return xsdDataContractImporter;
821 /// Load DataContract types which could be used in the code generator (shared types)
823 /// <param name="proxyOptions">Options controlling the generation</param>
824 /// <param name="typeLoader">Type loader to resolve referenced assemblies and types</param>
825 /// <param name="targetFrameworkVersion">Targetted Framework version number</param>
826 /// <param name="importErrors">Errors encountered while loading the shared data contracts</param>
828 /// A list of CLR types from referenced assemblies and/or specific types that we want to share
830 /// <remarks></remarks>
831 [SuppressMessage("Microsoft.Usage", "CA2301:EmbeddableTypesInContainersRule", MessageId = "sharedTypeTable", Justification = "This is used within VS to get the types from reference assemblies i.e., the reference assembly for a given assembly but not across assemblies - so com interop is not an issue.")]
832 protected static IEnumerable<Type> LoadSharedDataContractTypes(
833 ClientOptions proxyOptions, IContractGeneratorReferenceTypeLoader typeLoader, int targetFrameworkVersion, IList<ProxyGenerationError> importErrors)
835 if (typeLoader == null) throw new ArgumentNullException("typeLoader");
837 // the value in sharedTypeTable is why we add this type in the shared type list.
838 // 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
839 // 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.
840 Dictionary<Type, ReferencedType> sharedTypeTable = new Dictionary<Type, ReferencedType>();
842 // load all types in referencedAssemblies
843 IEnumerable<Assembly> referencedAssemblies = LoadReferenedAssemblies(proxyOptions, typeLoader, importErrors);
844 if (referencedAssemblies != null)
846 foreach (Assembly referencedAssembly in referencedAssemblies)
848 var typeLoader2 = typeLoader as IContractGeneratorReferenceTypeLoader2;
849 if (typeLoader2 != null)
851 foreach (Type sharedType in typeLoader2.LoadExportedTypes(referencedAssembly))
853 sharedTypeTable.Add(sharedType, null);
858 // Fall back to the original approach using IContractGeneratorReferenceTypeLoader.LoadType().
859 foreach (Type typeInAssembly in referencedAssembly.GetExportedTypes())
863 // Do multi-targeting check by calling IContractGeneratorReferenceTypeLoader.LoadType().
864 if (typeLoader.LoadType(typeInAssembly.FullName) != null)
866 sharedTypeTable.Add(typeInAssembly, null);
869 catch (NotSupportedException)
871 // NotSupportedException is thrown by multi-targeting check. It's normal if some types not existing in the current FX.
872 // So we can safely ---- it.
876 // fail to load one type in an assembly: warning message
878 new ProxyGenerationError(
879 ProxyGenerationError.GeneratorState.GenerateCode,
889 // load types in DataContractTypeList
890 foreach (ReferencedType referencedType in proxyOptions.ReferencedDataContractTypeList)
894 Type sharedType = typeLoader.LoadType(referencedType.TypeName);
897 if (!IsTypeShareable(sharedType))
900 new ProxyGenerationError(
901 ProxyGenerationError.GeneratorState.GenerateCode,
903 new FormatException(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_SharedTypeMustBePublic, referencedType.TypeName)))
908 sharedTypeTable[sharedType] = referencedType;
912 importErrors.Add(new ProxyGenerationError(
913 ProxyGenerationError.GeneratorState.GenerateCode,
919 // remove excluded types
920 foreach (ReferencedType excludedType in proxyOptions.ExcludedTypeList)
924 Type sharedType = typeLoader.LoadType(excludedType.TypeName);
926 if (sharedTypeTable.ContainsKey(sharedType))
928 if (sharedTypeTable[sharedType] != null)
931 importErrors.Add(new ProxyGenerationError(
932 ProxyGenerationError.GeneratorState.GenerateCode,
934 new Exception(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_DataContractExcludedAndIncluded, excludedType.TypeName))));
936 sharedTypeTable.Remove(sharedType);
941 // waring message for excludedTypes
942 importErrors.Add(new ProxyGenerationError(
943 ProxyGenerationError.GeneratorState.GenerateCode,
950 // remove unsupported types
951 foreach (Type unsupportedType in GetUnsupportedTypes(targetFrameworkVersion))
953 sharedTypeTable.Remove(unsupportedType);
956 return sharedTypeTable.Keys;
960 /// Get list of types which are not supported in the targetted framework.
962 /// <param name="targetFrameworkVersion">Targetted Framework version number</param>
963 /// <return></return>
964 /// <remarks></remarks>
965 private static IEnumerable<Type> GetUnsupportedTypes(int targetFrameworkVersion)
968 if (targetFrameworkVersion < FRAMEWORK_VERSION_35)
970 // NOTE: do we need load those types with typeLoader?
971 return unsupportedTypesInFramework30;
978 /// Ensure that the ConfigurationName attribute on service contracts and the channel endpoint elements all agree on the
979 /// name of the service contract.
980 /// We want to avoid having root/default namespace values persisted in config, since that would require us
981 /// to update config whenever the default/root namespace changes, so we make sure that we exclude it
982 /// from the ConfigurationName attribute and the channel endpoint element we generate.
984 /// For VB, the root namespace is not actually present in the generated code, so we typically don't have to
985 /// do anything (the configuration and proxy namespaces are equal) but for C#, we need to strip out the
986 /// default namespace.
988 /// <param name="proxyNamespace">
989 /// CLR namespace into which we will generate the service in the CodeCompileUnit
991 /// <param name="configNamespace">
992 /// The namespace that we expect to use in configuration.
994 /// <param name="generatedContracts">
995 /// The contracts that we have generated
997 /// <param name="endpoints">
998 /// All channel endpoints we have generated
1000 /// <param name="targetCompileUnit">
1001 /// The compile unit into which we generated the client
1003 private static void PatchConfigurationName(
1004 string proxyNamespace,
1005 string configNamespace,
1006 IEnumerable<GeneratedContractType> generatedContracts,
1007 IEnumerable<ChannelEndpointElement> endpoints,
1008 CodeCompileUnit targetCompileUnit
1012 // Since the name has to match between configuration and the name we put in the ConfigurationName
1013 // attribute in code, we may have some patching to do - but only if the proxy namespace is not equal
1014 // to the configuration namespace...
1015 if (configNamespace != null && !configNamespace.Equals(proxyNamespace, StringComparison.Ordinal))
1017 string proxyNamespaceHead = MakePeriodTerminatedNamespacePrefix(proxyNamespace);
1018 string configNamespaceHead = MakePeriodTerminatedNamespacePrefix(configNamespace);
1020 // We need to fix up the configuration name for all generated contracts...
1021 foreach (GeneratedContractType contract in generatedContracts)
1023 contract.ConfigurationName = ReplaceNamespace(proxyNamespaceHead, configNamespaceHead, contract.ConfigurationName);
1026 // ..and we need to fix up all elements in config...
1027 foreach (ChannelEndpointElement endpoint in endpoints)
1029 endpoint.Contract = ReplaceNamespace(proxyNamespaceHead, configNamespaceHead, endpoint.Contract);
1032 // ...and all ConfigurationName values in service contract attributes in the generated code as well...
1033 PatchConfigurationNameInServiceContractAttribute(targetCompileUnit, proxyNamespace, configNamespace);
1038 /// If the type name begins with the namespace specified in originalNamespace, replace the namespace
1039 /// for the given type name with the namespace specified in the replacementNamespace parameter.
1041 /// <param name="originalNamespace">
1042 /// Original namespace to look for.
1043 /// Must either be an empty string ("") or end with a period (".")
1045 /// <param name="replacementNamespace">
1046 /// Namespace to replace original namespace with
1047 /// Muse either be an empty string ("") or end with a period...
1049 /// <param name="typeName">Typename on which to do the replacement</param>
1051 /// The new type name (potentially the same as passed in)
1053 private static string ReplaceNamespace(string originalNamespace, string replacementNamespace, string typeName)
1055 Debug.Assert(originalNamespace.Length == 0 || originalNamespace.EndsWith(".", StringComparison.Ordinal));
1056 Debug.Assert(replacementNamespace.Length == 0 || replacementNamespace.EndsWith(".", StringComparison.Ordinal));
1057 Debug.Assert(typeName != null);
1059 if (typeName.StartsWith(originalNamespace, StringComparison.Ordinal))
1061 // Strip out the original namespace and replace it with the new namespace
1062 return replacementNamespace + typeName.Substring(originalNamespace.Length);
1071 /// Given the namespace, return either an empty string (if the given namespace was NULL or emtpy)
1072 /// or a period-terminated (".") string.
1074 /// <param name="ns"></param>
1076 /// Either an empty string or a string that ends with a period (".")
1077 /// Can never return Null...
1079 private static string MakePeriodTerminatedNamespacePrefix(string ns)
1081 if (String.IsNullOrEmpty(ns))
1085 else if (!ns.EndsWith(".", StringComparison.Ordinal))
1096 /// Determine if a type can be shared.
1098 /// In order for a type to be shareable for service references, it has to be a
1101 /// <param name="t"></param>
1102 /// <returns></returns>
1103 private static bool IsTypeShareable(Type t)
1107 System.Diagnostics.Debug.Fail("Why are you asking if a NULL type is shareable?");
1111 return t.IsPublic || t.IsNestedPublic;
1115 /// Load referenced assemblies
1117 /// <param name="proxyOptions"></param>
1118 /// <param name="typeLoader"></param>
1119 /// <param name="importErrors"></param>
1120 /// <return></return>
1121 /// <remarks></remarks>
1122 private static IEnumerable<Assembly> LoadReferenedAssemblies(ClientOptions proxyOptions, IContractGeneratorReferenceTypeLoader typeLoader, IList<ProxyGenerationError> importErrors)
1124 List<Assembly> referencedAssemblies = new List<Assembly>();
1125 if (proxyOptions.ReferenceAllAssemblies)
1129 IEnumerable<Exception> loadingErrors = null;
1130 IEnumerable<Assembly> allAssemblies = null;
1131 typeLoader.LoadAllAssemblies(out allAssemblies, out loadingErrors);
1132 if (loadingErrors != null)
1134 // treat as warning messages
1135 foreach (Exception ex in loadingErrors)
1137 importErrors.Add(new ProxyGenerationError(
1138 ProxyGenerationError.GeneratorState.GenerateCode,
1145 if (allAssemblies != null)
1147 referencedAssemblies.AddRange(allAssemblies);
1150 catch (Exception ex)
1152 importErrors.Add(new ProxyGenerationError(
1153 ProxyGenerationError.GeneratorState.GenerateCode,
1159 foreach (ReferencedAssembly referencedAssembly in proxyOptions.ReferencedAssemblyList)
1163 Assembly refAssembly = typeLoader.LoadAssembly(referencedAssembly.AssemblyName);
1164 if (refAssembly != null && !referencedAssemblies.Contains(refAssembly))
1166 referencedAssemblies.Add(refAssembly);
1169 catch (Exception ex)
1171 importErrors.Add(new ProxyGenerationError(
1172 ProxyGenerationError.GeneratorState.GenerateCode,
1177 return referencedAssemblies;
1181 /// Load the list of types that we have specified as collection types in our client options.
1182 /// The collection types will be used to generate collections in the data contracts.
1184 /// <param name="proxyOptions">Options specifying the list of collection types</param>
1185 /// <param name="typeLoader">Type loader that resolves type names to actual CLR types</param>
1186 /// <param name="importErrors">Errors encountered while loading the collection types</param>
1187 /// <return></return>
1188 /// <remarks></remarks>
1189 protected static IEnumerable<Type> LoadSharedCollectionTypes(ClientOptions proxyOptions, IContractGeneratorReferenceTypeLoader typeLoader, IList<ProxyGenerationError> importErrors)
1191 List<Type> referencedCollectionTypes = new List<Type>();
1192 foreach (ReferencedCollectionType referencedCollectionMapping in proxyOptions.CollectionMappingList)
1196 Type collectionType = typeLoader.LoadType(referencedCollectionMapping.TypeName);
1199 if (!IsTypeShareable(collectionType))
1202 new ProxyGenerationError(
1203 ProxyGenerationError.GeneratorState.GenerateCode,
1205 new FormatException(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_SharedTypeMustBePublic, referencedCollectionMapping.TypeName)))
1210 referencedCollectionTypes.Add(collectionType);
1212 catch (Exception ex)
1214 importErrors.Add(new ProxyGenerationError(
1215 ProxyGenerationError.GeneratorState.GenerateCode,
1220 return referencedCollectionTypes;
1224 /// Create an appropriate WsdlImporter for the generator
1226 /// <param name="svcMapFile"></param>
1227 /// <param name="toolConfiguration"></param>
1228 /// <param name="targetCompileUnit"></param>
1229 /// <param name="codeDomProvider"></param>
1230 /// <param name="targetNamespace"></param>
1231 /// <param name="typeLoader"></param>
1232 /// <param name="targetFrameworkVersion">Targetted Framework version number</param>
1233 /// <param name="importErrors"></param>
1234 /// <param name="typedDataSetSchemaImporterExtension"></param>
1235 /// <returns></returns>
1236 protected static WsdlImporter CreateWsdlImporter(SvcMapFile svcMapFile,
1237 System.Configuration.Configuration toolConfiguration,
1238 CodeCompileUnit targetCompileUnit,
1239 System.CodeDom.Compiler.CodeDomProvider codeDomProvider,
1240 string targetNamespace,
1241 IServiceProvider serviceProviderForImportExtensions,
1242 IContractGeneratorReferenceTypeLoader typeLoader,
1243 int targetFrameworkVersion,
1244 IList<ProxyGenerationError> importErrors,
1245 System.Type typedDataSetSchemaImporterExtension)
1247 List<MetadataSection> metadataSections = CollectMetadataDocuments(svcMapFile.MetadataList, importErrors);
1249 WsdlImporter importer = null;
1251 ClientOptions.ProxySerializerType serializerType = svcMapFile.ClientOptions.Serializer;
1252 if (serializerType == ClientOptions.ProxySerializerType.Auto && ContainsHttpBindings(metadataSections))
1254 // NOTE: HTTP Get/Post binding indicates an old web service. We use XmlSerializer to prevent generating dup classes.
1255 // Please check devdiv bug 94078
1256 serializerType = ClientOptions.ProxySerializerType.XmlSerializer;
1259 if (toolConfiguration != null)
1261 ServiceModelSectionGroup serviceModelSection = ServiceModelSectionGroup.GetSectionGroup(toolConfiguration);
1263 if (serviceModelSection != null)
1265 Collection<IWsdlImportExtension> wsdlImportExtensions = serviceModelSection.Client.Metadata.LoadWsdlImportExtensions();
1266 Collection<IPolicyImportExtension> policyImportExtensions = serviceModelSection.Client.Metadata.LoadPolicyImportExtensions();
1268 // If we have specified a specific serializer to use, we remove
1269 // the other serializer...
1270 switch (serializerType)
1272 case ClientOptions.ProxySerializerType.DataContractSerializer:
1273 RemoveExtension(typeof(XmlSerializerMessageContractImporter), wsdlImportExtensions);
1275 case ClientOptions.ProxySerializerType.XmlSerializer:
1276 RemoveExtension(typeof(DataContractSerializerMessageContractImporter), wsdlImportExtensions);
1278 case ClientOptions.ProxySerializerType.Auto:
1281 System.Diagnostics.Debug.Fail("Unknown serializer");
1285 ProvideImportExtensionsWithContextInformation(svcMapFile, serviceProviderForImportExtensions, wsdlImportExtensions, policyImportExtensions);
1287 wsdlImportExtensions.Add(new HttpBindingExtension());
1289 // Create Importer...
1290 importer = new WsdlImporter(new MetadataSet(metadataSections), policyImportExtensions, wsdlImportExtensions);
1294 if (importer == null)
1296 importer = new WsdlImporter(new MetadataSet(metadataSections));
1299 // DevDiv 124333 - Always add DataContract importer (even if we are in XmlSerializerMode) to
1300 // enable importing Fault contracts...
1301 importer.State.Add(typeof(System.Runtime.Serialization.XsdDataContractImporter),
1302 CreateDataContractImporter(svcMapFile.ClientOptions, targetCompileUnit, codeDomProvider, targetNamespace, typeLoader, targetFrameworkVersion, importErrors));
1304 if (serializerType != ClientOptions.ProxySerializerType.DataContractSerializer)
1306 importer.State.Add(typeof(System.ServiceModel.Channels.XmlSerializerImportOptions),
1307 CreateXmlSerializerImportOptions(svcMapFile.ClientOptions,
1311 typedDataSetSchemaImporterExtension));
1314 // Read the UseSerializerForFaults from Reference.svcmap, create a FaultImportOptions using this information
1315 // and pass it to WSDL Importer.
1316 FaultImportOptions faultOptions = new FaultImportOptions();
1317 faultOptions.UseMessageFormat = svcMapFile.ClientOptions.UseSerializerForFaults;
1318 importer.State.Add(typeof(System.ServiceModel.FaultImportOptions), faultOptions);
1320 // Read the WrappedOptions from Reference.svcmap, create a WrappedOptions using this information
1321 // and pass it to WSDL Importer.
1322 WrappedOptions wrappedOptions = new WrappedOptions();
1323 wrappedOptions.WrappedFlag = svcMapFile.ClientOptions.Wrapped;
1324 importer.State.Add(typeof(System.ServiceModel.Channels.WrappedOptions), wrappedOptions);
1330 /// Look through all the import extensions to see if any of them want access to
1331 /// the service reference's extension files. They tell us this by implementing
1332 /// the interface IWcfReferenceReceiveContextInformation.
1334 /// <param name="svcMapFile"></param>
1335 /// <param name="serviceProviderForImportExtensions"></param>
1336 /// <param name="wsdlImportExtensions"></param>
1337 /// <param name="policyImportExtensions"></param>
1338 internal static void ProvideImportExtensionsWithContextInformation(SvcMapFile svcMapFile, IServiceProvider serviceProviderForImportExtensions, IEnumerable<IWsdlImportExtension> wsdlImportExtensions, IEnumerable<IPolicyImportExtension> policyImportExtensions)
1340 // Only make this copy if we need to (not the mainline case)
1341 Dictionary<string, byte[]> extensionFileContents = null;
1343 foreach (IWsdlImportExtension wsdlImportExtension in wsdlImportExtensions)
1345 System.Web.Compilation.IWcfReferenceReceiveContextInformation receiveContext =
1346 wsdlImportExtension as System.Web.Compilation.IWcfReferenceReceiveContextInformation;
1347 if (receiveContext != null)
1349 if (extensionFileContents == null)
1351 extensionFileContents = CreateDictionaryOfCopiedExtensionFiles(svcMapFile);
1353 receiveContext.ReceiveImportContextInformation(
1354 extensionFileContents,
1355 serviceProviderForImportExtensions);
1358 foreach (IPolicyImportExtension policyImportExtension in policyImportExtensions)
1360 System.Web.Compilation.IWcfReferenceReceiveContextInformation receiveContext =
1361 policyImportExtension as System.Web.Compilation.IWcfReferenceReceiveContextInformation;
1362 if (receiveContext != null)
1364 if (extensionFileContents == null)
1366 extensionFileContents = CreateDictionaryOfCopiedExtensionFiles(svcMapFile);
1368 receiveContext.ReceiveImportContextInformation(
1369 extensionFileContents,
1370 serviceProviderForImportExtensions);
1376 /// Remove specific wsdl importer extension
1378 /// <param name="extensionType">
1379 /// The extension to remove
1381 /// <param name="wsdlImportExtensions">
1382 /// The collection to remove the extension from
1384 /// <return></return>
1385 /// <remarks></remarks>
1386 private static void RemoveExtension(Type extensionType, Collection<IWsdlImportExtension> wsdlImportExtensions)
1388 Debug.Assert(wsdlImportExtensions != null);
1390 for (int i = 0; i < wsdlImportExtensions.Count; i++)
1392 if (wsdlImportExtensions[i].GetType() == extensionType)
1393 wsdlImportExtensions.RemoveAt(i);
1398 /// Creates a dictionary containing a copy of the contents of all of the extension files
1400 /// <returns></returns>
1401 private static Dictionary<string, byte[]> CreateDictionaryOfCopiedExtensionFiles(SvcMapFile svcMapFile)
1403 Dictionary<string, byte[]> extensionFileContents = new Dictionary<string, byte[]>();
1404 foreach (ExtensionFile extensionFile in svcMapFile.Extensions)
1406 // If the extension file was not successfully loaded, do not include it in the
1407 // collection. Users are more likely to expect that the extension file won't
1408 // be in the collection on an error than they are to assume they have to check
1409 // if the byte array we return is null or not.
1410 if (extensionFile.ContentBuffer != null && extensionFile.IsBufferValid)
1412 extensionFileContents.Add(extensionFile.Name, (byte[])extensionFile.ContentBuffer.Clone());
1416 return extensionFileContents;
1421 /// Merge metadata files to prepare code generation
1423 /// <returns>metadata collection</returns>
1424 /// <remarks></remarks>
1425 protected static List<MetadataSection> CollectMetadataDocuments(IEnumerable<MetadataFile> metadataList, IList<ProxyGenerationError> importErrors)
1427 List<MetadataSection> metadataCollection = new List<MetadataSection>();
1429 foreach (MetadataFile metadataItem in metadataList)
1431 if (!metadataItem.Ignore)
1435 MetadataSection metadataSection = metadataItem.CreateMetadataSection();
1436 if (metadataSection != null)
1438 metadataCollection.Add(metadataSection);
1441 catch (Exception ex)
1443 importErrors.Add(ConvertMetadataErrorToProxyGenerationError(metadataItem, ex));
1448 RemoveDuplicatedSchemaItems(metadataCollection, importErrors);
1449 CheckDuplicatedWsdlItems(metadataCollection, importErrors);
1451 return metadataCollection;
1455 /// Convert metadata loading errors into proxy generation error messages
1457 /// <return></return>
1458 /// <remarks></remarks>
1459 internal static ProxyGenerationError ConvertMetadataErrorToProxyGenerationError(MetadataFile metadataItem, Exception ex)
1461 ProxyGenerationError generationError = null;
1462 if (ex is XmlSchemaException)
1464 generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, (XmlSchemaException)ex);
1466 else if (ex is XmlException)
1468 generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, (XmlException)ex);
1470 else if (ex is InvalidOperationException)
1472 System.Xml.Schema.XmlSchemaException schemaException = ex.InnerException as System.Xml.Schema.XmlSchemaException;
1473 if (schemaException != null)
1475 generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, schemaException);
1479 System.Xml.XmlException xmlException = ex.InnerException as System.Xml.XmlException;
1480 if (xmlException != null)
1482 generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, xmlException);
1486 generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, (InvalidOperationException)ex);
1492 generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, ex);
1494 return generationError;
1498 /// Remove duplicated schema items from the metadata collection
1500 /// <remarks></remarks>
1501 private static void RemoveDuplicatedSchemaItems(List<MetadataSection> metadataCollection, IList<ProxyGenerationError> importErrors)
1503 Dictionary<XmlSchema, MetadataSection> schemaList = new Dictionary<XmlSchema, MetadataSection>();
1505 // add independent schema files...
1506 foreach (MetadataSection metadataSection in metadataCollection)
1508 if (metadataSection.Dialect == MetadataSection.XmlSchemaDialect)
1510 XmlSchema schema = (XmlSchema)metadataSection.Metadata;
1511 schemaList.Add(schema, metadataSection);
1515 // add embedded files...
1516 foreach (MetadataSection metadataSection in metadataCollection)
1518 if (metadataSection.Dialect == MetadataSection.ServiceDescriptionDialect)
1520 System.Web.Services.Description.ServiceDescription wsdl = (System.Web.Services.Description.ServiceDescription)metadataSection.Metadata;
1521 foreach (XmlSchema schema in wsdl.Types.Schemas)
1523 schema.SourceUri = wsdl.RetrievalUrl;
1524 schemaList.Add(schema, metadataSection);
1529 IEnumerable<XmlSchema> duplicatedSchemas;
1530 SchemaMerger.MergeSchemas(schemaList.Keys, importErrors, out duplicatedSchemas);
1532 if (duplicatedSchemas != null)
1534 foreach (XmlSchema schema in duplicatedSchemas)
1536 Debug.Assert(schemaList.ContainsKey(schema), "The schema list should not contain any of the schemas returned in the duplicateSchemas...");
1538 MetadataSection metadataSection = schemaList[schema];
1539 if (metadataSection.Dialect == MetadataSection.XmlSchemaDialect)
1541 metadataCollection.Remove(metadataSection);
1543 else if (metadataSection.Dialect == MetadataSection.ServiceDescriptionDialect)
1545 System.Web.Services.Description.ServiceDescription wsdl = (System.Web.Services.Description.ServiceDescription)metadataSection.Metadata;
1546 wsdl.Types.Schemas.Remove(schema);
1553 /// check all wsdl files, and generate error messages if one contract have multiple different specifications
1555 /// <remarks></remarks>
1556 private static void CheckDuplicatedWsdlItems(IList<MetadataSection> metadataCollection, IList<ProxyGenerationError> importErrors)
1558 List<System.Web.Services.Description.ServiceDescription> wsdlFiles = new List<System.Web.Services.Description.ServiceDescription>();
1559 foreach (MetadataSection metadataSection in metadataCollection)
1561 if (metadataSection.Dialect == MetadataSection.ServiceDescriptionDialect)
1563 System.Web.Services.Description.ServiceDescription wsdl = (System.Web.Services.Description.ServiceDescription)metadataSection.Metadata;
1564 wsdlFiles.Add(wsdl);
1568 WsdlInspector.CheckDuplicatedWsdlItems(wsdlFiles, importErrors);
1572 /// Given a WSDL importer, a set of metadata files and a compile unit, import the metadata
1575 /// <param name="importer"></param>
1576 /// <param name="compileUnit"></param>
1577 /// <param name="generationErrors">
1578 /// Errors encountered whie importing the model. Any new errors will be appended to this list.
1580 /// <param name="serviceEndpointList">List of endpoints imported</param>
1581 /// <param name="bindingCollection">The collection of bindings imported</param>
1582 /// <param name="contractCollection">The collection of contracts imported</param>
1583 protected static void ImportWCFModel(WsdlImporter importer,
1584 System.CodeDom.CodeCompileUnit compileUnit,
1585 IList<ProxyGenerationError> generationErrors,
1586 out List<ServiceEndpoint> serviceEndpointList,
1587 out IEnumerable<System.ServiceModel.Channels.Binding> bindingCollection,
1588 out IEnumerable<ContractDescription> contractCollection)
1590 // We want to remove soap1.2 endpoints for ASMX references, but we can't use the "normal" way
1591 // of using a IWsdlImportExtension to do so since BeforeImport is called too late (DevDiv 7857)
1592 // If DevDiv 7857 is fixed, we can remove the following two lines and instead add the
1593 // AsmxEndpointPickerExtension to the importer's wsdl import extensions...
1594 IWsdlImportExtension asmxFixerUpper = new AsmxEndpointPickerExtension();
1595 asmxFixerUpper.BeforeImport(importer.WsdlDocuments, null, null);
1597 // NOTE: we should import Endpoint before Contracts, otherwise some information (related to binding) will be lost in the model (devdiv: 22396)
1598 serviceEndpointList = new List<ServiceEndpoint>();
1601 // First we import all the endpoints (ports). This is required so that any WsdlImportExtension's BeforeImport
1602 // gets called before we actually try to import anything from the WSDL object model.
1603 // If we don't do this, we run into problems if any wsdl import extensions want to delete a specific port
1604 // and this port happens to be the first port we try to import (you can't interrupt the import)
1605 importer.ImportAllEndpoints();
1608 // We need to go through each endpoint element and "re-import" it in order to get the mapping
1609 // between the wsdlPort and the ServiceEndpoint... Importing the same endpoint twice is a no-op
1610 // as far as the endpoint collection is concerned - it is simply a hashtable lookup to retreive
1611 // the already generated information...
1613 foreach (System.Web.Services.Description.ServiceDescription wsdlServiceDescription in importer.WsdlDocuments)
1615 foreach (System.Web.Services.Description.Service wsdlService in wsdlServiceDescription.Services)
1617 foreach (System.Web.Services.Description.Port servicePort in wsdlService.Ports)
1621 ServiceEndpoint newEndpoint = importer.ImportEndpoint(servicePort);
1622 serviceEndpointList.Add(newEndpoint);
1624 catch (InvalidOperationException)
1626 // Invalid operation exceptions should already be in the errors collection for the importer, so we don't
1627 // need to add another generationError. The most probable cause for this is that the we failed to import
1630 catch (Exception ex)
1631 { // It is bad, because WsdlImporter.WsdlImportException is a private class
1632 generationErrors.Add(new ProxyGenerationError(ProxyGenerationError.GeneratorState.GenerateCode, wsdlServiceDescription.RetrievalUrl, ex));
1639 bindingCollection = importer.ImportAllBindings();
1640 System.Diagnostics.Debug.Assert(bindingCollection != null, "The importer should never return a NULL binding collection!");
1642 contractCollection = importer.ImportAllContracts();
1643 System.Diagnostics.Debug.Assert(contractCollection != null, "The importer should never return a NULL contract collection!");
1645 foreach (MetadataConversionError error in importer.Errors)
1647 generationErrors.Add(new ProxyGenerationError(error));
1654 /// This function patches ServiceContractAttribute in the generated proxy code. It replaces all proxyNamespace in the attribute
1655 /// to configNamespace. The configNamespace does not depend on defaultNamespace of the project.
1657 /// <param name="proxyNamespace"></param>
1658 /// <param name="configNamespace"></param>
1659 /// <return></return>
1660 /// <remarks></remarks>
1661 private static void PatchConfigurationNameInServiceContractAttribute(CodeCompileUnit proxyCodeUnit, string proxyNamespace, string configNamespace)
1663 if (proxyNamespace == null)
1665 proxyNamespace = String.Empty;
1668 string proxyNamespaceHead = MakePeriodTerminatedNamespacePrefix(proxyNamespace);
1669 string configNamespaceHead = MakePeriodTerminatedNamespacePrefix(configNamespace);
1671 if (proxyCodeUnit != null)
1673 foreach (CodeNamespace proxyCodeNamespace in proxyCodeUnit.Namespaces)
1675 // Find the namespace we are patching...
1676 if (String.Equals(proxyNamespace, proxyCodeNamespace.Name, StringComparison.Ordinal))
1678 // ...and all types in each namespace...
1679 foreach (CodeTypeDeclaration typeDeclaration in proxyCodeNamespace.Types)
1681 if (typeDeclaration.IsInterface)
1683 // ...and each attribute on each interface...
1684 foreach (CodeAttributeDeclaration codeAttribute in typeDeclaration.CustomAttributes)
1686 // find System.ServiceModel.ServiceContractAttribute attribute.
1687 if (String.Equals(codeAttribute.AttributeType.BaseType, typeof(System.ServiceModel.ServiceContractAttribute).FullName, StringComparison.Ordinal))
1689 foreach (CodeAttributeArgument argument in codeAttribute.Arguments)
1691 if (String.Equals(argument.Name, "ConfigurationName", StringComparison.Ordinal))
1693 // we only fix the string here
1694 CodePrimitiveExpression valueExpression = argument.Value as CodePrimitiveExpression;
1695 if (valueExpression != null && valueExpression.Value is string)
1697 valueExpression.Value = ReplaceNamespace(proxyNamespaceHead, configNamespaceHead, (string)valueExpression.Value);
1712 /// Patch VB code for output parameters.
1714 /// Visual Basic doesn't support Out parameters - they are all generated as ByRef.
1715 /// Unfortunately, the CodeDom provider doesn't add an Out attribute to the ByRef
1716 /// parameters, so we have to do that ourselves...
1718 /// <param name="codeCompileUnit"></param>
1719 /// <remarks></remarks>
1720 private static void PatchOutParametersInVB(CodeCompileUnit codeCompileUnit)
1722 foreach (CodeNamespace codeNamespace in codeCompileUnit.Namespaces)
1724 foreach (CodeTypeDeclaration codeClass in codeNamespace.Types)
1726 PatchTypeDeclaration(codeClass);
1732 /// Patch TypeDeclaration in VB code for output parameters
1734 /// <param name="codeClass"></param>
1735 /// <remarks></remarks>
1736 private static void PatchTypeDeclaration(CodeTypeDeclaration codeClass)
1738 foreach (CodeTypeMember member in codeClass.Members)
1740 if (member is CodeTypeDeclaration)
1742 // Recurse down in nested types...
1743 PatchTypeDeclaration((CodeTypeDeclaration)member);
1745 else if (member is CodeMemberMethod)
1747 CodeMemberMethod method = member as CodeMemberMethod;
1748 foreach (CodeParameterDeclarationExpression parameter in method.Parameters)
1750 if (parameter.Direction == FieldDirection.Out)
1752 // Make sure that all Out parameters have an <Out> attribute
1754 // First check for explicit <OutAttribute> declaration to avoid adding duplicate attributes.
1755 if (!IsDefinedInCodeAttributeCollection(typeof(System.Runtime.InteropServices.OutAttribute), parameter.CustomAttributes))
1757 parameter.CustomAttributes.Add(OutAttribute);
1766 /// check whether code attribuate has already been declared.
1768 /// <param name="type"></param>
1769 /// <param name="metadata"></param>
1770 /// <return></return>
1771 /// <remarks></remarks>
1772 private static bool IsDefinedInCodeAttributeCollection(Type type, CodeAttributeDeclarationCollection metadata)
1774 foreach (CodeAttributeDeclaration attribute in metadata)
1776 if (String.Equals(attribute.Name, type.FullName, StringComparison.Ordinal) || String.Equals(attribute.Name, type.Name, StringComparison.Ordinal))
1785 /// Check whether it is VB language
1787 /// <param name="codeDomProvider"></param>
1788 /// <return></return>
1789 /// <remarks></remarks>
1790 private static bool IsVBCodeDomProvider(System.CodeDom.Compiler.CodeDomProvider codeDomProvider)
1792 string fileExtension = codeDomProvider.FileExtension;
1795 string language = System.CodeDom.Compiler.CodeDomProvider.GetLanguageFromExtension(fileExtension);
1796 return String.Equals(language, VB_LANGUAGE_NAME, StringComparison.OrdinalIgnoreCase);
1798 catch (System.Configuration.ConfigurationException)
1800 // not defined extension
1806 /// check whether HTTP Binding is used in those metadata files
1808 /// <param name="metadataCollection">metadata files</param>
1809 /// <return></return>
1810 /// <remarks></remarks>
1811 private static bool ContainsHttpBindings(IEnumerable<MetadataSection> metadataCollection)
1813 foreach (MetadataSection metadataSection in metadataCollection)
1815 if (metadataSection.Dialect == MetadataSection.ServiceDescriptionDialect)
1817 System.Web.Services.Description.ServiceDescription wsdlFile = (System.Web.Services.Description.ServiceDescription)metadataSection.Metadata;
1818 if (ContainsHttpBindings(wsdlFile))
1828 /// check whether HTTP Binding is used in one wsdl file
1830 /// <param name="wsdlFile">one wsdl</param>
1831 /// <return></return>
1832 /// <remarks></remarks>
1833 internal static bool ContainsHttpBindings(System.Web.Services.Description.ServiceDescription wsdlFile)
1835 foreach (System.Web.Services.Description.Binding binding in wsdlFile.Bindings)
1837 foreach (object extension in binding.Extensions)
1839 System.Web.Services.Description.HttpBinding httpBinding = extension as System.Web.Services.Description.HttpBinding;
1840 if (httpBinding != null)