Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Web.Extensions / Compilation / WCFModel / VSWCFServiceContractGenerator.cs
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.
5 /// </copyright>
6 #endregion
7
8 using System.CodeDom;
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;
18 using System.Xml;
19 using System.Xml.Schema;
20 using System.Security.Permissions;
21 using System.Linq;
22
23 #if WEB_EXTENSIONS_CODE
24 using System.Security;
25 using System.Web.Resources;
26 #else
27 using Microsoft.VSDesigner.WCF.Resources;
28 #endif
29
30 ///
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
34 /// 
35 using Debug = System.Diagnostics.Debug;
36 using System.Diagnostics.CodeAnalysis;
37
38 #if WEB_EXTENSIONS_CODE
39 namespace System.Web.Compilation.WCFModel
40 #else
41 namespace Microsoft.VSDesigner.WCFModel
42 #endif
43 {
44     /// <summary>
45     /// Proxy and configuration generator
46     /// </summary>
47 #if WEB_EXTENSIONS_CODE
48     [PermissionSet(SecurityAction.InheritanceDemand, Name="FullTrust")]    
49     [SecurityCritical]
50     internal class VSWCFServiceContractGenerator
51 #else
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
54     [CLSCompliant(true)]
55     [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
56     [PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")]
57     public class VSWCFServiceContractGenerator
58 #endif
59     {
60
61         #region Private backing fields
62         private const string VB_LANGUAGE_NAME = "vb";
63
64         /// <summary>
65         /// Collection to hold all bindings generated by this generator
66         /// </summary>
67         private IEnumerable<System.ServiceModel.Channels.Binding> bindingCollection;
68
69         /// <summary>
70         /// Collection to hold all contracts generated by this generator
71         /// </summary>
72         private IEnumerable<ContractDescription> contractCollection;
73
74         /// <summary>
75         /// Collection to hold all endpoints generated by this generator
76         /// </summary>
77         private List<ServiceEndpoint> serviceEndpointList;
78
79         /// <summary>
80         /// Map from service endpoint to the channel endpoint that was actually imported
81         /// </summary>
82         private Dictionary<ServiceEndpoint, ChannelEndpointElement> serviceEndpointToChannelEndpointElementMap;
83
84         /// <summary>
85         /// List of contract types generate by this generator
86         /// </summary>
87         private List<GeneratedContractType> proxyGeneratedContractTypes;
88
89         /// <summary>
90         /// The target compile unit that contains the proxy and data contracts
91         /// </summary>
92         private CodeCompileUnit targetCompileUnit;
93
94         /// <summary>
95         /// Configuration object that we inserterd bindings and endpoints from the
96         /// current service into. May be Null/Nothing.
97         /// </summary>
98         private System.Configuration.Configuration targetConfiguration;
99
100         /// <summary>
101         /// Errors encountered while generating the proxy
102         /// </summary>
103         private IEnumerable<ProxyGenerationError> proxyGenerationErrors;
104
105         /// <summary>
106         /// Errors encountered while importing the metadata..
107         /// </summary>
108         private IList<ProxyGenerationError> importErrors;
109
110         /// <summary>
111         /// Helper property that is added to Out parameters for VB
112         /// </summary>
113         private static CodeAttributeDeclaration outAttribute;
114
115         /// <summary>
116         /// version number for 3.5 framework
117         /// </summary>
118         private const int FRAMEWORK_VERSION_35 = 0x30005;
119
120         /// <summary>
121         /// list of types which are new in the 3.5 framework. 
122         /// </summary>
123         private static Type[] unsupportedTypesInFramework30 = new Type[] {
124             typeof(DateTimeOffset),
125         };
126
127
128         #endregion
129
130         #region Public read-only properties
131
132         /// <summary>
133         /// The collection of bindings generated by this generator
134         /// </summary>
135         /// <value></value>
136         /// <remarks>
137         /// </remarks>
138         public IEnumerable<System.ServiceModel.Channels.Binding> BindingCollection
139         {
140             get
141             {
142                 System.Diagnostics.Debug.Assert(bindingCollection != null);
143                 return bindingCollection;
144             }
145         }
146
147         /// <summary>
148         /// The collection of generated contract types
149         /// </summary>
150         public IEnumerable<GeneratedContractType> ProxyGeneratedContractTypes
151         {
152             get
153             {
154                 System.Diagnostics.Debug.Assert(proxyGeneratedContractTypes != null);
155                 return proxyGeneratedContractTypes;
156             }
157         }
158
159         /// <summary>
160         /// The collection of errors encountered while generating the
161         /// proxy. For errors related to the metadata import, use the
162         /// ImportErrors property
163         /// </summary>
164         public IEnumerable<ProxyGenerationError> ProxyGenerationErrors
165         {
166             get
167             {
168                 System.Diagnostics.Debug.Assert(proxyGenerationErrors != null);
169                 return proxyGenerationErrors;
170             }
171         }
172
173         /// <summary>
174         /// The collection of errors encountered while importing metadata.
175         /// For errors related to the proxy and config generation, use the
176         /// ProxyGenerationErrors property
177         /// </summary>
178         public IEnumerable<ProxyGenerationError> ImportErrors
179         {
180             get
181             {
182                 System.Diagnostics.Debug.Assert(importErrors != null);
183                 return importErrors;
184             }
185         }
186
187         /// <summary>
188         /// The collection of contracts imported by this generator
189         /// </summary>
190         /// <value></value>
191         /// <remarks></remarks>
192         public IEnumerable<ContractDescription> ContractCollection
193         {
194             get
195             {
196                 System.Diagnostics.Debug.Assert(contractCollection != null);
197                 return contractCollection;
198             }
199         }
200
201         /// <summary>
202         /// Collection of Endpoints in the service model generated by
203         /// this generator
204         /// </summary>
205         /// <value></value>
206         /// <remarks></remarks>
207         public IEnumerable<ServiceEndpoint> EndpointCollection
208         {
209             get
210             {
211                 System.Diagnostics.Debug.Assert(serviceEndpointList != null);
212                 return serviceEndpointList;
213             }
214         }
215
216         /// <summary>
217         /// Map from service endpoints to its corresponding channel endpoint configuration
218         /// element
219         /// </summary>
220         public Dictionary<ServiceEndpoint, ChannelEndpointElement> EndpointMap
221         {
222             get
223             {
224                 System.Diagnostics.Debug.Assert(serviceEndpointToChannelEndpointElementMap != null);
225                 return serviceEndpointToChannelEndpointElementMap;
226             }
227         }
228
229         /// <summary>
230         /// The configuratin into which we inject the bindings and endpoints. May be null/Nothing
231         /// if no target configuration was provided.
232         /// </summary>
233         public System.Configuration.Configuration TargetConfiguration
234         {
235             get
236             {
237                 // Note: it is valid for this to be NULL. Caller beware!
238                 return targetConfiguration;
239             }
240         }
241
242         /// <summary>
243         /// CodeCompileUnit containing the generated data contracts, service contracts
244         /// and WCF client.
245         /// </summary>
246         public CodeCompileUnit TargetCompileUnit
247         {
248             get
249             {
250                 System.Diagnostics.Debug.Assert(targetCompileUnit != null);
251                 return targetCompileUnit;
252             }
253         }
254
255         #endregion
256
257         /// <summary>
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
260         /// as ByRef)
261         /// </summary>
262         private static CodeAttributeDeclaration OutAttribute
263         {
264             get
265             {
266                 if (outAttribute == null)
267                 {
268                     outAttribute = new CodeAttributeDeclaration(typeof(System.Runtime.InteropServices.OutAttribute).FullName);
269                 }
270                 return outAttribute;
271             }
272         }
273
274         /// <summary>
275         /// protected constructor to block creating instance directly.
276         /// </summary>
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)
296         {
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");
306
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;
316         }
317
318         /// <summary>
319         /// Factory method: generate code and return the resulting VSWCFServiceContractGenerator. 
320         /// </summary>
321         /// <param name="svcMapFile">
322         /// The SvcMapFile that lists the metadata and generation options for the service reference.
323         /// </param>
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.
327         /// </param>
328         /// <param name="codeDomProvider">
329         /// CodeDom provider that is to be used to generate the client code.
330         /// </param>
331         /// <param name="proxyNamespace">
332         /// CLR namespace in which to generate the client code.
333         /// </param>
334         /// <param name="targetConfiguration">
335         /// The configuration into which we will put bindings/endpoints for this service
336         /// reference. May be Null/Nothing.
337         /// </param>
338         /// <param name="configurationNamespace">
339         /// The namespace that is to be used in configuration for this service reference.
340         /// </param>
341         /// <param name="serviceProviderForImportExtensions">
342         /// Service provider that we'll pass on to import extensions that accept our site:ing
343         /// mechanism
344         /// </param>
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.
348         /// </param>
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.
351         /// </param>
352         /// <param name="typedDataSetSchemaImporterExtension">
353         /// Schema importer extension to be used for typed datasets.
354         /// </param>
355         /// <returns>
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.
358         /// </returns>
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)
369         {
370             if (svcMapFile == null) throw new ArgumentNullException("svcMapFile");
371             if (codeDomProvider == null) throw new ArgumentNullException("codeDomProvider");
372             if (typedDataSetSchemaImporterExtension == null) throw new ArgumentNullException("typedDataSetSchemaImporterExtension");
373
374             List<ProxyGenerationError> importErrors = new List<ProxyGenerationError>();
375             List<ProxyGenerationError> proxyGenerationErrors = new List<ProxyGenerationError>();
376
377             CodeCompileUnit targetCompileUnit = new CodeCompileUnit();
378
379             WsdlImporter wsdlImporter = CreateWsdlImporter(svcMapFile,
380                                                            toolConfiguration,
381                                                            targetCompileUnit,
382                                                            codeDomProvider,
383                                                            proxyNamespace,
384                                                            serviceProviderForImportExtensions,
385                                                            typeLoader,
386                                                            targetFrameworkVersion,
387                                                            importErrors,
388                                                            typedDataSetSchemaImporterExtension);
389
390             ServiceContractGenerator contractGenerator = CreateContractGenerator(svcMapFile.ClientOptions,
391                                                                                 wsdlImporter,
392                                                                                 targetCompileUnit,
393                                                                                 proxyNamespace,
394                                                                                 targetConfiguration,
395                                                                                 typeLoader,
396                                                                                 targetFrameworkVersion,
397                                                                                 importErrors);
398
399             try
400             {
401                 List<ServiceEndpoint> serviceEndpointList = new List<ServiceEndpoint>();
402                 IEnumerable<System.ServiceModel.Channels.Binding> bindingCollection;
403                 IEnumerable<ContractDescription> contractCollection;
404
405                 ImportWCFModel(wsdlImporter,
406                                  targetCompileUnit,
407                                  importErrors,
408                                  out serviceEndpointList,
409                                  out bindingCollection,
410                                  out contractCollection);
411
412                 Dictionary<ServiceEndpoint, ChannelEndpointElement> serviceEndpointToChannelEndpointElementMap;
413                 List<GeneratedContractType> proxyGeneratedContractTypes;
414
415                 GenerateProxy(wsdlImporter,
416                               contractGenerator,
417                               targetCompileUnit,
418                               proxyNamespace,
419                               configurationNamespace,
420                               contractCollection,
421                               bindingCollection,
422                               serviceEndpointList,
423                               proxyGenerationErrors,
424                               out serviceEndpointToChannelEndpointElementMap,
425                               out proxyGeneratedContractTypes);
426
427                 if (IsVBCodeDomProvider(codeDomProvider))
428                 {
429                     PatchOutParametersInVB(targetCompileUnit);
430                 }
431
432                 return new VSWCFServiceContractGenerator(importErrors,
433                                                          targetCompileUnit,
434                                                          targetConfiguration,
435                                                          bindingCollection,
436                                                          contractCollection,
437                                                          serviceEndpointList,
438                                                          serviceEndpointToChannelEndpointElementMap,
439                                                          proxyGeneratedContractTypes,
440                                                          proxyGenerationErrors);
441             }
442             catch (Exception ex)
443             {
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,
449                                     String.Empty,
450                                     ex,
451                                     false));
452
453                 return new VSWCFServiceContractGenerator(importErrors,
454                                                         new CodeCompileUnit(),
455                                                         targetConfiguration,
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);
462             }
463
464         }
465
466
467         /// <summary>
468         /// Instantiate and configure a ServiceContractGenerator to be used for code and config
469         /// generation.
470         /// </summary>
471         /// <param name="proxyOptions">
472         /// Options set in the SvcMap file to control the code/config generation.
473         /// </param>
474         /// <param name="wsdlImporter">
475         /// The WsdlImporter that is to be used to import the metadata for this service reference.
476         /// </param>
477         /// <param name="targetCompileUnit">
478         /// Compile unit into which we will generate the client code
479         /// </param>
480         /// <param name="proxyNamespace">
481         /// The CLR namespace into which we will generate the client code.
482         /// </param>
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.
486         /// </param>
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.
490         /// </param>
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.
493         /// </param>
494         /// <param name="importErrors">
495         /// The list into which we will add any errors while importing the metadata.
496         /// </param>
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)
506         {
507             ServiceContractGenerator contractGenerator = new ServiceContractGenerator(targetCompileUnit, targetConfiguration);
508
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);
513
514             if (proxyOptions.GenerateInternalTypes)
515             {
516                 contractGenerator.Options |= ServiceContractGenerationOptions.InternalTypes;
517             }
518             else
519             {
520                 contractGenerator.Options &= ~ServiceContractGenerationOptions.InternalTypes;
521             }
522
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;
527
528             if (proxyOptions.GenerateTaskBasedAsynchronousMethod)
529             {
530                 contractGenerator.Options |= ServiceContractGenerationOptions.TaskBasedAsynchronousMethod;
531             }
532             else if (proxyOptions.GenerateAsynchronousMethods)
533             {
534                 contractGenerator.Options |= ServiceContractGenerationOptions.AsynchronousMethods;
535                 if (targetFrameworkVersion >= FRAMEWORK_VERSION_35)
536                 {
537                     contractGenerator.Options |= ServiceContractGenerationOptions.EventBasedAsynchronousMethods;
538                 }
539             }
540
541             if (proxyOptions.GenerateMessageContracts)
542             {
543                 contractGenerator.Options |= ServiceContractGenerationOptions.TypedMessages;
544             }
545             else
546             {
547                 contractGenerator.Options &= ~ServiceContractGenerationOptions.TypedMessages;
548             }
549
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)
553             {
554                 foreach (ContractMapping mapping in proxyOptions.ServiceContractMappingList)
555                 {
556                     try
557                     {
558                         Type sharedType = typeLoader.LoadType(mapping.TypeName);
559
560                         // verify that the type is shareable - if not, we generate an error...
561                         if (!IsTypeShareable(sharedType))
562                         {
563                             importErrors.Add(
564                                     new ProxyGenerationError(
565                                         ProxyGenerationError.GeneratorState.GenerateCode,
566                                         String.Empty,
567                                         new FormatException(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_SharedTypeMustBePublic, mapping.TypeName)))
568                                 );
569                             continue;
570                         }
571
572                         // Get a contract description corresponding to the type we wanted to share
573                         ContractDescription contract = ContractDescription.GetContract(sharedType);
574
575                         if (!String.Equals(mapping.Name, contract.Name, StringComparison.Ordinal) ||
576                                 !String.Equals(mapping.TargetNamespace, contract.Namespace, StringComparison.Ordinal))
577                         {
578                             // mismatch
579                             importErrors.Add(
580                                     new ProxyGenerationError(
581                                         ProxyGenerationError.GeneratorState.GenerateCode,
582                                         String.Empty,
583                                         new FormatException(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_ServiceContractMappingMissMatch, mapping.TypeName, contract.Namespace, contract.Name, mapping.TargetNamespace, mapping.Name)))
584                                 );
585                         }
586
587                         XmlQualifiedName qname = new XmlQualifiedName(contract.Name, contract.Namespace);
588                         wsdlImporter.KnownContracts.Add(qname, contract);
589                         contractGenerator.ReferencedTypes.Add(contract, sharedType);
590                     }
591                     catch (Exception ex)
592                     {
593                         importErrors.Add(new ProxyGenerationError(
594                                         ProxyGenerationError.GeneratorState.GenerateCode,
595                                         String.Empty,
596                                         ex));
597                     }
598                 }
599             }
600
601             foreach (NamespaceMapping namespaceMapping in proxyOptions.NamespaceMappingList)
602             {
603                 contractGenerator.NamespaceMappings.Add(namespaceMapping.TargetNamespace, namespaceMapping.ClrNamespace);
604             }
605
606             return contractGenerator;
607         }
608
609         /// <summary>
610         /// Generate Proxy Code and (if available) configuration
611         /// </summary>
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)
633         {
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");
639
640             proxyGeneratedContractTypes = new List<GeneratedContractType>();
641             serviceEndpointToChannelEndpointElementMap = new Dictionary<ServiceEndpoint, ChannelEndpointElement>();
642
643             try
644             {
645                 HttpBindingExtension httpBindingEx = importer.WsdlImportExtensions.Find<HttpBindingExtension>();
646
647                 foreach (ContractDescription contract in contractCollection)
648                 {
649                     if (httpBindingEx == null || !httpBindingEx.IsHttpBindingContract(contract) || serviceEndpointList.Any(endpoint => endpoint.Contract == contract))
650                     {
651                         CodeTypeReference typeReference = contractGenerator.GenerateServiceContractType(contract);
652                         if (typeReference != null)
653                         {
654                             // keep the (targetNamespace, portType) -> CLR type map table...
655
656                             string baseType = typeReference.BaseType;
657
658                             GeneratedContractType generatedType = new GeneratedContractType(contract.Namespace, contract.Name, baseType, baseType);
659                             proxyGeneratedContractTypes.Add(generatedType);
660                         }
661                     }
662                 }
663
664                 // We should only import the Binding & Endpoints if there is a configuration storage...
665                 if (contractGenerator.Configuration != null)
666                 {
667                     foreach (ServiceEndpoint endpoint in serviceEndpointList)
668                     {
669                         ChannelEndpointElement endpointElement = null;
670                         contractGenerator.GenerateServiceEndpoint(endpoint, out endpointElement);
671                         serviceEndpointToChannelEndpointElementMap[endpoint] = endpointElement;
672                     }
673
674                     foreach (System.ServiceModel.Channels.Binding bindingDescription in bindingCollection)
675                     {
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);
680                     }
681
682                 }
683
684                 PatchConfigurationName(proxyNamespace,
685                                        configurationNamespace,
686                                        proxyGeneratedContractTypes,
687                                        serviceEndpointToChannelEndpointElementMap.Values,
688                                        targetCompileUnit);
689             }
690             finally
691             {
692                 foreach (MetadataConversionError error in contractGenerator.Errors)
693                 {
694                     proxyGenerationErrors.Add(new ProxyGenerationError(error));
695                 }
696             }
697         }
698
699         /// <summary>
700         /// Create appropriate XmlSerializerImportOptions for the generator
701         /// </summary>
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)
713         {
714             System.ServiceModel.Channels.XmlSerializerImportOptions xmlSerializerOptions = new XmlSerializerImportOptions(targetCompileUnit);
715             System.Web.Services.Description.WebReferenceOptions webReferenceOptions = new System.Web.Services.Description.WebReferenceOptions();
716
717             webReferenceOptions.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateProperties | System.Xml.Serialization.CodeGenerationOptions.GenerateOrder;
718
719             if (proxyOptions.EnableDataBinding)
720             {
721                 webReferenceOptions.CodeGenerationOptions |= System.Xml.Serialization.CodeGenerationOptions.EnableDataBinding;
722             }
723
724             webReferenceOptions.SchemaImporterExtensions.Add(typedDataSetSchemaImporterExtension.AssemblyQualifiedName);
725             webReferenceOptions.SchemaImporterExtensions.Add(typeof(System.Data.DataSetSchemaImporterExtension).AssemblyQualifiedName);
726
727             /* 
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745 */
746
747             xmlSerializerOptions.WebReferenceOptions = webReferenceOptions;
748             xmlSerializerOptions.CodeProvider = codeDomProvider;
749
750             xmlSerializerOptions.ClrNamespace = proxyNamespace;
751
752             return xmlSerializerOptions;
753         }
754
755         /// <summary>
756         /// Create an appropriate XsdDataContractImporter for the generator
757         /// </summary>
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)
774         {
775             System.Runtime.Serialization.XsdDataContractImporter xsdDataContractImporter = new System.Runtime.Serialization.XsdDataContractImporter(targetCompileUnit);
776             System.Runtime.Serialization.ImportOptions options = new System.Runtime.Serialization.ImportOptions();
777
778             options.CodeProvider = codeDomProvider;
779
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;
787
788             if (typeLoader != null)
789             {
790                 IEnumerable<Type> referencedTypes = LoadSharedDataContractTypes(proxyOptions, typeLoader, targetFrameworkVersion, importErrors);
791                 if (referencedTypes != null)
792                 {
793                     foreach (Type sharedType in referencedTypes)
794                     {
795                         options.ReferencedTypes.Add(sharedType);
796                     }
797                 }
798
799                 IEnumerable<Type> referencedCollectionTypes = LoadSharedCollectionTypes(proxyOptions, typeLoader, importErrors);
800                 if (referencedCollectionTypes != null)
801                 {
802                     foreach (Type collectionType in referencedCollectionTypes)
803                     {
804                         options.ReferencedCollectionTypes.Add(collectionType);
805                     }
806                 }
807
808             }
809
810             foreach (NamespaceMapping namespaceMapping in proxyOptions.NamespaceMappingList)
811             {
812                 options.Namespaces.Add(namespaceMapping.TargetNamespace, namespaceMapping.ClrNamespace);
813             }
814
815             xsdDataContractImporter.Options = options;
816
817             return xsdDataContractImporter;
818         }
819
820         /// <summary>
821         /// Load DataContract types which could be used in the code generator (shared types)
822         /// </summary>
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>
827         /// <return>
828         /// A list of CLR types from referenced assemblies and/or specific types that we want to share
829         /// </return>
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)
834         {
835             if (typeLoader == null) throw new ArgumentNullException("typeLoader");
836
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>();
841
842             // load all types in referencedAssemblies
843             IEnumerable<Assembly> referencedAssemblies = LoadReferenedAssemblies(proxyOptions, typeLoader, importErrors);
844             if (referencedAssemblies != null)
845             {
846                 foreach (Assembly referencedAssembly in referencedAssemblies)
847                 {
848                     var typeLoader2 = typeLoader as IContractGeneratorReferenceTypeLoader2;
849                     if (typeLoader2 != null)
850                     {
851                         foreach (Type sharedType in typeLoader2.LoadExportedTypes(referencedAssembly))
852                         {
853                             sharedTypeTable.Add(sharedType, null);
854                         }
855                     }
856                     else
857                     {
858                         // Fall back to the original approach using IContractGeneratorReferenceTypeLoader.LoadType().
859                         foreach (Type typeInAssembly in referencedAssembly.GetExportedTypes())
860                         {
861                             try
862                             {
863                                 // Do multi-targeting check by calling IContractGeneratorReferenceTypeLoader.LoadType().                            
864                                 if (typeLoader.LoadType(typeInAssembly.FullName) != null)
865                                 {
866                                     sharedTypeTable.Add(typeInAssembly, null);
867                                 }
868                             }
869                             catch (NotSupportedException)
870                             {
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.
873                             }
874                             catch (Exception ex)
875                             {
876                                 // fail to load one type in an assembly: warning message
877                                 importErrors.Add(
878                                     new ProxyGenerationError(
879                                         ProxyGenerationError.GeneratorState.GenerateCode,
880                                         String.Empty,
881                                         ex,
882                                         true));
883                             }
884                         }
885                     }
886                 }
887             }
888
889             // load types in DataContractTypeList
890             foreach (ReferencedType referencedType in proxyOptions.ReferencedDataContractTypeList)
891             {
892                 try
893                 {
894                     Type sharedType = typeLoader.LoadType(referencedType.TypeName);
895
896                     // verify...
897                     if (!IsTypeShareable(sharedType))
898                     {
899                         importErrors.Add(
900                                 new ProxyGenerationError(
901                                     ProxyGenerationError.GeneratorState.GenerateCode,
902                                     String.Empty,
903                                     new FormatException(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_SharedTypeMustBePublic, referencedType.TypeName)))
904                             );
905                         continue;
906                     }
907
908                     sharedTypeTable[sharedType] = referencedType;
909                 }
910                 catch (Exception ex)
911                 {
912                     importErrors.Add(new ProxyGenerationError(
913                                     ProxyGenerationError.GeneratorState.GenerateCode,
914                                     String.Empty,
915                                     ex));
916                 }
917             }
918
919             // remove excluded types
920             foreach (ReferencedType excludedType in proxyOptions.ExcludedTypeList)
921             {
922                 try
923                 {
924                     Type sharedType = typeLoader.LoadType(excludedType.TypeName);
925
926                     if (sharedTypeTable.ContainsKey(sharedType))
927                     {
928                         if (sharedTypeTable[sharedType] != null)
929                         {
930                             // error message
931                             importErrors.Add(new ProxyGenerationError(
932                                             ProxyGenerationError.GeneratorState.GenerateCode,
933                                             String.Empty,
934                                             new Exception(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_DataContractExcludedAndIncluded, excludedType.TypeName))));
935                         }
936                         sharedTypeTable.Remove(sharedType);
937                     }
938                 }
939                 catch (Exception ex)
940                 {
941                     // waring message for excludedTypes
942                     importErrors.Add(new ProxyGenerationError(
943                                     ProxyGenerationError.GeneratorState.GenerateCode,
944                                     String.Empty,
945                                     ex,
946                                     true));
947                 }
948             }
949
950             // remove unsupported types
951             foreach (Type unsupportedType in GetUnsupportedTypes(targetFrameworkVersion))
952             {
953                 sharedTypeTable.Remove(unsupportedType);
954             }
955
956             return sharedTypeTable.Keys;
957         }
958
959         /// <summary>
960         /// Get list of types which are not supported in the targetted framework.
961         /// </summary>
962         /// <param name="targetFrameworkVersion">Targetted Framework version number</param>
963         /// <return></return>
964         /// <remarks></remarks>
965         private static IEnumerable<Type> GetUnsupportedTypes(int targetFrameworkVersion)
966         {
967
968             if (targetFrameworkVersion < FRAMEWORK_VERSION_35)
969             {
970                 // NOTE: do we need load those types with typeLoader?
971                 return unsupportedTypesInFramework30;
972             }
973
974             return new Type[0];
975         }
976
977         /// <summary>
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.
983         /// 
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.
987         /// </summary>
988         /// <param name="proxyNamespace">
989         /// CLR namespace into which we will generate the service in the CodeCompileUnit
990         /// </param>
991         /// <param name="configNamespace">
992         /// The namespace that we expect to use in configuration.
993         /// </param>
994         /// <param name="generatedContracts">
995         /// The contracts that we have generated
996         /// </param>
997         /// <param name="endpoints">
998         /// All channel endpoints we have generated
999         /// </param>
1000         /// <param name="targetCompileUnit">
1001         /// The compile unit into which we generated the client
1002         /// </param>
1003         private static void PatchConfigurationName(
1004                                     string proxyNamespace,
1005                                     string configNamespace,
1006                                     IEnumerable<GeneratedContractType> generatedContracts,
1007                                     IEnumerable<ChannelEndpointElement> endpoints,
1008                                     CodeCompileUnit targetCompileUnit
1009             )
1010         {
1011
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))
1016             {
1017                 string proxyNamespaceHead = MakePeriodTerminatedNamespacePrefix(proxyNamespace);
1018                 string configNamespaceHead = MakePeriodTerminatedNamespacePrefix(configNamespace);
1019
1020                 // We need to fix up the configuration name for all generated contracts...
1021                 foreach (GeneratedContractType contract in generatedContracts)
1022                 {
1023                     contract.ConfigurationName = ReplaceNamespace(proxyNamespaceHead, configNamespaceHead, contract.ConfigurationName);
1024                 }
1025
1026                 // ..and we need to fix up all elements in config...
1027                 foreach (ChannelEndpointElement endpoint in endpoints)
1028                 {
1029                     endpoint.Contract = ReplaceNamespace(proxyNamespaceHead, configNamespaceHead, endpoint.Contract);
1030                 }
1031
1032                 // ...and all ConfigurationName values in service contract attributes in the generated code as well...
1033                 PatchConfigurationNameInServiceContractAttribute(targetCompileUnit, proxyNamespace, configNamespace);
1034             }
1035         }
1036
1037         /// <summary>
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.
1040         /// </summary>
1041         /// <param name="originalNamespace">
1042         /// Original namespace to look for.
1043         /// Must either be an empty string ("") or end with a period (".")
1044         /// </param>
1045         /// <param name="replacementNamespace">
1046         /// Namespace to replace original namespace with
1047         /// Muse either be an empty string ("") or end with a period...
1048         /// </param>
1049         /// <param name="typeName">Typename on which to do the replacement</param>
1050         /// <returns>
1051         /// The new type name (potentially the same as passed in)
1052         /// </returns>
1053         private static string ReplaceNamespace(string originalNamespace, string replacementNamespace, string typeName)
1054         {
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);
1058
1059             if (typeName.StartsWith(originalNamespace, StringComparison.Ordinal))
1060             {
1061                 // Strip out the original namespace and replace it with the new namespace
1062                 return replacementNamespace + typeName.Substring(originalNamespace.Length);
1063             }
1064             else
1065             {
1066                 return typeName;
1067             }
1068         }
1069
1070         /// <summary>
1071         /// Given the namespace, return either an empty string (if the given namespace was NULL or emtpy)
1072         /// or a period-terminated (".") string.
1073         /// </summary>
1074         /// <param name="ns"></param>
1075         /// <returns>
1076         /// Either an empty string or a string that ends with a period (".")
1077         /// Can never return Null...
1078         /// </returns>
1079         private static string MakePeriodTerminatedNamespacePrefix(string ns)
1080         {
1081             if (String.IsNullOrEmpty(ns))
1082             {
1083                 return "";
1084             }
1085             else if (!ns.EndsWith(".", StringComparison.Ordinal))
1086             {
1087                 return ns + ".";
1088             }
1089             else
1090             {
1091                 return ns;
1092             }
1093         }
1094
1095         /// <summary>
1096         /// Determine if a type can be shared.
1097         /// 
1098         /// In order for a type to be shareable for service references, it has to be a 
1099         /// public type...
1100         /// </summary>
1101         /// <param name="t"></param>
1102         /// <returns></returns>
1103         private static bool IsTypeShareable(Type t)
1104         {
1105             if (t == null)
1106             {
1107                 System.Diagnostics.Debug.Fail("Why are you asking if a NULL type is shareable?");
1108                 return false;
1109             }
1110
1111             return t.IsPublic || t.IsNestedPublic;
1112         }
1113
1114         /// <summary>
1115         /// Load referenced assemblies
1116         /// </summary>
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)
1123         {
1124             List<Assembly> referencedAssemblies = new List<Assembly>();
1125             if (proxyOptions.ReferenceAllAssemblies)
1126             {
1127                 try
1128                 {
1129                     IEnumerable<Exception> loadingErrors = null;
1130                     IEnumerable<Assembly> allAssemblies = null;
1131                     typeLoader.LoadAllAssemblies(out allAssemblies, out loadingErrors);
1132                     if (loadingErrors != null)
1133                     {
1134                         // treat as warning messages
1135                         foreach (Exception ex in loadingErrors)
1136                         {
1137                             importErrors.Add(new ProxyGenerationError(
1138                                             ProxyGenerationError.GeneratorState.GenerateCode,
1139                                             String.Empty,
1140                                             ex,
1141                                             true));
1142                         }
1143                     }
1144
1145                     if (allAssemblies != null)
1146                     {
1147                         referencedAssemblies.AddRange(allAssemblies);
1148                     }
1149                 }
1150                 catch (Exception ex)
1151                 {
1152                     importErrors.Add(new ProxyGenerationError(
1153                                     ProxyGenerationError.GeneratorState.GenerateCode,
1154                                     String.Empty,
1155                                     ex));
1156                 }
1157             }
1158
1159             foreach (ReferencedAssembly referencedAssembly in proxyOptions.ReferencedAssemblyList)
1160             {
1161                 try
1162                 {
1163                     Assembly refAssembly = typeLoader.LoadAssembly(referencedAssembly.AssemblyName);
1164                     if (refAssembly != null && !referencedAssemblies.Contains(refAssembly))
1165                     {
1166                         referencedAssemblies.Add(refAssembly);
1167                     }
1168                 }
1169                 catch (Exception ex)
1170                 {
1171                     importErrors.Add(new ProxyGenerationError(
1172                                     ProxyGenerationError.GeneratorState.GenerateCode,
1173                                     String.Empty,
1174                                     ex));
1175                 }
1176             }
1177             return referencedAssemblies;
1178         }
1179
1180         /// <summary>
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.
1183         /// </summary>
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)
1190         {
1191             List<Type> referencedCollectionTypes = new List<Type>();
1192             foreach (ReferencedCollectionType referencedCollectionMapping in proxyOptions.CollectionMappingList)
1193             {
1194                 try
1195                 {
1196                     Type collectionType = typeLoader.LoadType(referencedCollectionMapping.TypeName);
1197
1198                     // verify...
1199                     if (!IsTypeShareable(collectionType))
1200                     {
1201                         importErrors.Add(
1202                                 new ProxyGenerationError(
1203                                     ProxyGenerationError.GeneratorState.GenerateCode,
1204                                     String.Empty,
1205                                     new FormatException(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_SharedTypeMustBePublic, referencedCollectionMapping.TypeName)))
1206                             );
1207                         continue;
1208                     }
1209
1210                     referencedCollectionTypes.Add(collectionType);
1211                 }
1212                 catch (Exception ex)
1213                 {
1214                     importErrors.Add(new ProxyGenerationError(
1215                                     ProxyGenerationError.GeneratorState.GenerateCode,
1216                                     String.Empty,
1217                                     ex));
1218                 }
1219             }
1220             return referencedCollectionTypes;
1221         }
1222
1223         /// <summary>
1224         /// Create an appropriate WsdlImporter for the generator
1225         /// </summary>
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)
1246         {
1247             List<MetadataSection> metadataSections = CollectMetadataDocuments(svcMapFile.MetadataList, importErrors);
1248
1249             WsdlImporter importer = null;
1250
1251             ClientOptions.ProxySerializerType serializerType = svcMapFile.ClientOptions.Serializer;
1252             if (serializerType == ClientOptions.ProxySerializerType.Auto && ContainsHttpBindings(metadataSections))
1253             {
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;
1257             }
1258
1259             if (toolConfiguration != null)
1260             {
1261                 ServiceModelSectionGroup serviceModelSection = ServiceModelSectionGroup.GetSectionGroup(toolConfiguration);
1262
1263                 if (serviceModelSection != null)
1264                 {
1265                     Collection<IWsdlImportExtension> wsdlImportExtensions = serviceModelSection.Client.Metadata.LoadWsdlImportExtensions();
1266                     Collection<IPolicyImportExtension> policyImportExtensions = serviceModelSection.Client.Metadata.LoadPolicyImportExtensions();
1267
1268                     // If we have specified a specific serializer to use, we remove
1269                     // the other serializer...
1270                     switch (serializerType)
1271                     {
1272                         case ClientOptions.ProxySerializerType.DataContractSerializer:
1273                             RemoveExtension(typeof(XmlSerializerMessageContractImporter), wsdlImportExtensions);
1274                             break;
1275                         case ClientOptions.ProxySerializerType.XmlSerializer:
1276                             RemoveExtension(typeof(DataContractSerializerMessageContractImporter), wsdlImportExtensions);
1277                             break;
1278                         case ClientOptions.ProxySerializerType.Auto:
1279                             break;
1280                         default:
1281                             System.Diagnostics.Debug.Fail("Unknown serializer");
1282                             break;
1283                     }
1284
1285                     ProvideImportExtensionsWithContextInformation(svcMapFile, serviceProviderForImportExtensions, wsdlImportExtensions, policyImportExtensions);
1286
1287                     wsdlImportExtensions.Add(new HttpBindingExtension());
1288
1289                     // Create Importer...
1290                     importer = new WsdlImporter(new MetadataSet(metadataSections), policyImportExtensions, wsdlImportExtensions);
1291                 }
1292             }
1293
1294             if (importer == null)
1295             {
1296                 importer = new WsdlImporter(new MetadataSet(metadataSections));
1297             }
1298
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));
1303
1304             if (serializerType != ClientOptions.ProxySerializerType.DataContractSerializer)
1305             {
1306                 importer.State.Add(typeof(System.ServiceModel.Channels.XmlSerializerImportOptions),
1307                                CreateXmlSerializerImportOptions(svcMapFile.ClientOptions,
1308                                                                 targetCompileUnit,
1309                                                                 codeDomProvider,
1310                                                                 targetNamespace,
1311                                                                 typedDataSetSchemaImporterExtension));
1312             }
1313
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);
1319
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);
1325
1326             return importer;
1327         }
1328
1329         /// <summary>
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.
1333         /// </summary>
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)
1339         {
1340             // Only make this copy if we need to (not the mainline case)
1341             Dictionary<string, byte[]> extensionFileContents = null;
1342
1343             foreach (IWsdlImportExtension wsdlImportExtension in wsdlImportExtensions)
1344             {
1345                 System.Web.Compilation.IWcfReferenceReceiveContextInformation receiveContext =
1346                     wsdlImportExtension as System.Web.Compilation.IWcfReferenceReceiveContextInformation;
1347                 if (receiveContext != null)
1348                 {
1349                     if (extensionFileContents == null)
1350                     {
1351                         extensionFileContents = CreateDictionaryOfCopiedExtensionFiles(svcMapFile);
1352                     }
1353                     receiveContext.ReceiveImportContextInformation(
1354                         extensionFileContents,
1355                         serviceProviderForImportExtensions);
1356                 }
1357             }
1358             foreach (IPolicyImportExtension policyImportExtension in policyImportExtensions)
1359             {
1360                 System.Web.Compilation.IWcfReferenceReceiveContextInformation receiveContext =
1361                     policyImportExtension as System.Web.Compilation.IWcfReferenceReceiveContextInformation;
1362                 if (receiveContext != null)
1363                 {
1364                     if (extensionFileContents == null)
1365                     {
1366                         extensionFileContents = CreateDictionaryOfCopiedExtensionFiles(svcMapFile);
1367                     }
1368                     receiveContext.ReceiveImportContextInformation(
1369                         extensionFileContents,
1370                         serviceProviderForImportExtensions);
1371                 }
1372             }
1373         }
1374
1375         /// <summary>
1376         /// Remove specific wsdl importer extension
1377         /// </summary>
1378         /// <param name="extensionType">
1379         /// The extension to remove
1380         /// </param>
1381         /// <param name="wsdlImportExtensions">
1382         /// The collection to remove the extension from
1383         /// </param>
1384         /// <return></return>
1385         /// <remarks></remarks>
1386         private static void RemoveExtension(Type extensionType, Collection<IWsdlImportExtension> wsdlImportExtensions)
1387         {
1388             Debug.Assert(wsdlImportExtensions != null);
1389
1390             for (int i = 0; i < wsdlImportExtensions.Count; i++)
1391             {
1392                 if (wsdlImportExtensions[i].GetType() == extensionType)
1393                     wsdlImportExtensions.RemoveAt(i);
1394             }
1395         }
1396
1397         /// <summary>
1398         /// Creates a dictionary containing a copy of the contents of all of the extension files
1399         /// </summary>
1400         /// <returns></returns>
1401         private static Dictionary<string, byte[]> CreateDictionaryOfCopiedExtensionFiles(SvcMapFile svcMapFile)
1402         {
1403             Dictionary<string, byte[]> extensionFileContents = new Dictionary<string, byte[]>();
1404             foreach (ExtensionFile extensionFile in svcMapFile.Extensions)
1405             {
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)
1411                 {
1412                     extensionFileContents.Add(extensionFile.Name, (byte[])extensionFile.ContentBuffer.Clone());
1413                 }
1414             }
1415
1416             return extensionFileContents;
1417         }
1418
1419
1420         /// <summary>
1421         /// Merge metadata files to prepare code generation
1422         /// </summary>
1423         /// <returns>metadata collection</returns>
1424         /// <remarks></remarks>
1425         protected static List<MetadataSection> CollectMetadataDocuments(IEnumerable<MetadataFile> metadataList, IList<ProxyGenerationError> importErrors)
1426         {
1427             List<MetadataSection> metadataCollection = new List<MetadataSection>();
1428
1429             foreach (MetadataFile metadataItem in metadataList)
1430             {
1431                 if (!metadataItem.Ignore)
1432                 {
1433                     try
1434                     {
1435                         MetadataSection metadataSection = metadataItem.CreateMetadataSection();
1436                         if (metadataSection != null)
1437                         {
1438                             metadataCollection.Add(metadataSection);
1439                         }
1440                     }
1441                     catch (Exception ex)
1442                     {
1443                         importErrors.Add(ConvertMetadataErrorToProxyGenerationError(metadataItem, ex));
1444                     }
1445                 }
1446             }
1447
1448             RemoveDuplicatedSchemaItems(metadataCollection, importErrors);
1449             CheckDuplicatedWsdlItems(metadataCollection, importErrors);
1450
1451             return metadataCollection;
1452         }
1453
1454         /// <summary>
1455         /// Convert metadata loading errors into proxy generation error messages
1456         /// </summary>
1457         /// <return></return>
1458         /// <remarks></remarks>
1459         internal static ProxyGenerationError ConvertMetadataErrorToProxyGenerationError(MetadataFile metadataItem, Exception ex)
1460         {
1461             ProxyGenerationError generationError = null;
1462             if (ex is XmlSchemaException)
1463             {
1464                 generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, (XmlSchemaException)ex);
1465             }
1466             else if (ex is XmlException)
1467             {
1468                 generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, (XmlException)ex);
1469             }
1470             else if (ex is InvalidOperationException)
1471             {
1472                 System.Xml.Schema.XmlSchemaException schemaException = ex.InnerException as System.Xml.Schema.XmlSchemaException;
1473                 if (schemaException != null)
1474                 {
1475                     generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, schemaException);
1476                 }
1477                 else
1478                 {
1479                     System.Xml.XmlException xmlException = ex.InnerException as System.Xml.XmlException;
1480                     if (xmlException != null)
1481                     {
1482                         generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, xmlException);
1483                     }
1484                     else
1485                     {
1486                         generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, (InvalidOperationException)ex);
1487                     }
1488                 }
1489             }
1490             else
1491             {
1492                 generationError = new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata, metadataItem.FileName, ex);
1493             }
1494             return generationError;
1495         }
1496
1497         /// <summary>
1498         /// Remove duplicated schema items from the metadata collection
1499         /// </summary>
1500         /// <remarks></remarks>
1501         private static void RemoveDuplicatedSchemaItems(List<MetadataSection> metadataCollection, IList<ProxyGenerationError> importErrors)
1502         {
1503             Dictionary<XmlSchema, MetadataSection> schemaList = new Dictionary<XmlSchema, MetadataSection>();
1504
1505             // add independent schema files...
1506             foreach (MetadataSection metadataSection in metadataCollection)
1507             {
1508                 if (metadataSection.Dialect == MetadataSection.XmlSchemaDialect)
1509                 {
1510                     XmlSchema schema = (XmlSchema)metadataSection.Metadata;
1511                     schemaList.Add(schema, metadataSection);
1512                 }
1513             }
1514
1515             // add embedded files...
1516             foreach (MetadataSection metadataSection in metadataCollection)
1517             {
1518                 if (metadataSection.Dialect == MetadataSection.ServiceDescriptionDialect)
1519                 {
1520                     System.Web.Services.Description.ServiceDescription wsdl = (System.Web.Services.Description.ServiceDescription)metadataSection.Metadata;
1521                     foreach (XmlSchema schema in wsdl.Types.Schemas)
1522                     {
1523                         schema.SourceUri = wsdl.RetrievalUrl;
1524                         schemaList.Add(schema, metadataSection);
1525                     }
1526                 }
1527             }
1528
1529             IEnumerable<XmlSchema> duplicatedSchemas;
1530             SchemaMerger.MergeSchemas(schemaList.Keys, importErrors, out duplicatedSchemas);
1531
1532             if (duplicatedSchemas != null)
1533             {
1534                 foreach (XmlSchema schema in duplicatedSchemas)
1535                 {
1536                     Debug.Assert(schemaList.ContainsKey(schema), "The schema list should not contain any of the schemas returned in the duplicateSchemas...");
1537
1538                     MetadataSection metadataSection = schemaList[schema];
1539                     if (metadataSection.Dialect == MetadataSection.XmlSchemaDialect)
1540                     {
1541                         metadataCollection.Remove(metadataSection);
1542                     }
1543                     else if (metadataSection.Dialect == MetadataSection.ServiceDescriptionDialect)
1544                     {
1545                         System.Web.Services.Description.ServiceDescription wsdl = (System.Web.Services.Description.ServiceDescription)metadataSection.Metadata;
1546                         wsdl.Types.Schemas.Remove(schema);
1547                     }
1548                 }
1549             }
1550         }
1551
1552         /// <summary>
1553         /// check all wsdl files, and generate error messages if one contract have multiple different specifications
1554         /// </summary>
1555         /// <remarks></remarks>
1556         private static void CheckDuplicatedWsdlItems(IList<MetadataSection> metadataCollection, IList<ProxyGenerationError> importErrors)
1557         {
1558             List<System.Web.Services.Description.ServiceDescription> wsdlFiles = new List<System.Web.Services.Description.ServiceDescription>();
1559             foreach (MetadataSection metadataSection in metadataCollection)
1560             {
1561                 if (metadataSection.Dialect == MetadataSection.ServiceDescriptionDialect)
1562                 {
1563                     System.Web.Services.Description.ServiceDescription wsdl = (System.Web.Services.Description.ServiceDescription)metadataSection.Metadata;
1564                     wsdlFiles.Add(wsdl);
1565                 }
1566             }
1567
1568             WsdlInspector.CheckDuplicatedWsdlItems(wsdlFiles, importErrors);
1569         }
1570
1571         /// <summary>
1572         /// Given a WSDL importer, a set of metadata files and a compile unit, import the metadata
1573         /// files.
1574         /// </summary>
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.
1579         /// </param>
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)
1589         {
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);
1596
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>();
1599
1600             //
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();
1606
1607             //
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...
1612             //
1613             foreach (System.Web.Services.Description.ServiceDescription wsdlServiceDescription in importer.WsdlDocuments)
1614             {
1615                 foreach (System.Web.Services.Description.Service wsdlService in wsdlServiceDescription.Services)
1616                 {
1617                     foreach (System.Web.Services.Description.Port servicePort in wsdlService.Ports)
1618                     {
1619                         try
1620                         {
1621                             ServiceEndpoint newEndpoint = importer.ImportEndpoint(servicePort);
1622                             serviceEndpointList.Add(newEndpoint);
1623                         }
1624                         catch (InvalidOperationException)
1625                         {
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 
1628                             // the endpoint...
1629                         }
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));
1633                         }
1634                     }
1635                 }
1636             }
1637
1638
1639             bindingCollection = importer.ImportAllBindings();
1640             System.Diagnostics.Debug.Assert(bindingCollection != null, "The importer should never return a NULL binding collection!");
1641
1642             contractCollection = importer.ImportAllContracts();
1643             System.Diagnostics.Debug.Assert(contractCollection != null, "The importer should never return a NULL contract collection!");
1644
1645             foreach (MetadataConversionError error in importer.Errors)
1646             {
1647                 generationErrors.Add(new ProxyGenerationError(error));
1648             }
1649         }
1650
1651
1652
1653         /// <summary>
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.
1656         /// </summary>
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)
1662         {
1663             if (proxyNamespace == null)
1664             {
1665                 proxyNamespace = String.Empty;
1666             }
1667
1668             string proxyNamespaceHead = MakePeriodTerminatedNamespacePrefix(proxyNamespace);
1669             string configNamespaceHead = MakePeriodTerminatedNamespacePrefix(configNamespace);
1670
1671             if (proxyCodeUnit != null)
1672             {
1673                 foreach (CodeNamespace proxyCodeNamespace in proxyCodeUnit.Namespaces)
1674                 {
1675                     // Find the namespace we are patching...
1676                     if (String.Equals(proxyNamespace, proxyCodeNamespace.Name, StringComparison.Ordinal))
1677                     {
1678                         // ...and all types in each namespace...
1679                         foreach (CodeTypeDeclaration typeDeclaration in proxyCodeNamespace.Types)
1680                         {
1681                             if (typeDeclaration.IsInterface)
1682                             {
1683                                 // ...and each attribute on each interface...
1684                                 foreach (CodeAttributeDeclaration codeAttribute in typeDeclaration.CustomAttributes)
1685                                 {
1686                                     // find System.ServiceModel.ServiceContractAttribute attribute.
1687                                     if (String.Equals(codeAttribute.AttributeType.BaseType, typeof(System.ServiceModel.ServiceContractAttribute).FullName, StringComparison.Ordinal))
1688                                     {
1689                                         foreach (CodeAttributeArgument argument in codeAttribute.Arguments)
1690                                         {
1691                                             if (String.Equals(argument.Name, "ConfigurationName", StringComparison.Ordinal))
1692                                             {
1693                                                 // we only fix the string here
1694                                                 CodePrimitiveExpression valueExpression = argument.Value as CodePrimitiveExpression;
1695                                                 if (valueExpression != null && valueExpression.Value is string)
1696                                                 {
1697                                                     valueExpression.Value = ReplaceNamespace(proxyNamespaceHead, configNamespaceHead, (string)valueExpression.Value);
1698                                                 }
1699                                             }
1700                                         }
1701                                     }
1702                                 }
1703                             }
1704                         }
1705                     }
1706                 }
1707             }
1708         }
1709
1710
1711         /// <summary>
1712         /// Patch VB code for output parameters.
1713         /// 
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...
1717         /// </summary>
1718         /// <param name="codeCompileUnit"></param>
1719         /// <remarks></remarks>
1720         private static void PatchOutParametersInVB(CodeCompileUnit codeCompileUnit)
1721         {
1722             foreach (CodeNamespace codeNamespace in codeCompileUnit.Namespaces)
1723             {
1724                 foreach (CodeTypeDeclaration codeClass in codeNamespace.Types)
1725                 {
1726                     PatchTypeDeclaration(codeClass);
1727                 }
1728             }
1729         }
1730
1731         /// <summary>
1732         /// Patch TypeDeclaration in VB code for output parameters
1733         /// </summary>
1734         /// <param name="codeClass"></param>
1735         /// <remarks></remarks>
1736         private static void PatchTypeDeclaration(CodeTypeDeclaration codeClass)
1737         {
1738             foreach (CodeTypeMember member in codeClass.Members)
1739             {
1740                 if (member is CodeTypeDeclaration)
1741                 {
1742                     // Recurse down in nested types...
1743                     PatchTypeDeclaration((CodeTypeDeclaration)member);
1744                 }
1745                 else if (member is CodeMemberMethod)
1746                 {
1747                     CodeMemberMethod method = member as CodeMemberMethod;
1748                     foreach (CodeParameterDeclarationExpression parameter in method.Parameters)
1749                     {
1750                         if (parameter.Direction == FieldDirection.Out)
1751                         {
1752                             // Make sure that all Out parameters have an <Out> attribute
1753                             //
1754                             // First check for explicit <OutAttribute> declaration to avoid adding duplicate attributes.
1755                             if (!IsDefinedInCodeAttributeCollection(typeof(System.Runtime.InteropServices.OutAttribute), parameter.CustomAttributes))
1756                             {
1757                                 parameter.CustomAttributes.Add(OutAttribute);
1758                             }
1759                         }
1760                     }
1761                 }
1762             }
1763         }
1764
1765         /// <summary>
1766         /// check whether code attribuate has already been declared.
1767         /// </summary>
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)
1773         {
1774             foreach (CodeAttributeDeclaration attribute in metadata)
1775             {
1776                 if (String.Equals(attribute.Name, type.FullName, StringComparison.Ordinal) || String.Equals(attribute.Name, type.Name, StringComparison.Ordinal))
1777                 {
1778                     return true;
1779                 }
1780             }
1781             return false;
1782         }
1783
1784         /// <summary>
1785         /// Check whether it is VB language
1786         /// </summary>
1787         /// <param name="codeDomProvider"></param>
1788         /// <return></return>
1789         /// <remarks></remarks>
1790         private static bool IsVBCodeDomProvider(System.CodeDom.Compiler.CodeDomProvider codeDomProvider)
1791         {
1792             string fileExtension = codeDomProvider.FileExtension;
1793             try
1794             {
1795                 string language = System.CodeDom.Compiler.CodeDomProvider.GetLanguageFromExtension(fileExtension);
1796                 return String.Equals(language, VB_LANGUAGE_NAME, StringComparison.OrdinalIgnoreCase);
1797             }
1798             catch (System.Configuration.ConfigurationException)
1799             {
1800                 // not defined extension
1801                 return false;
1802             }
1803         }
1804
1805         /// <summary>
1806         /// check whether HTTP Binding is used in those metadata files
1807         /// </summary>
1808         /// <param name="metadataCollection">metadata files</param>
1809         /// <return></return>
1810         /// <remarks></remarks>
1811         private static bool ContainsHttpBindings(IEnumerable<MetadataSection> metadataCollection)
1812         {
1813             foreach (MetadataSection metadataSection in metadataCollection)
1814             {
1815                 if (metadataSection.Dialect == MetadataSection.ServiceDescriptionDialect)
1816                 {
1817                     System.Web.Services.Description.ServiceDescription wsdlFile = (System.Web.Services.Description.ServiceDescription)metadataSection.Metadata;
1818                     if (ContainsHttpBindings(wsdlFile))
1819                     {
1820                         return true;
1821                     }
1822                 }
1823             }
1824             return false;
1825         }
1826
1827         /// <summary>
1828         /// check whether HTTP Binding is used in one wsdl file
1829         /// </summary>
1830         /// <param name="wsdlFile">one wsdl</param>
1831         /// <return></return>
1832         /// <remarks></remarks>
1833         internal static bool ContainsHttpBindings(System.Web.Services.Description.ServiceDescription wsdlFile)
1834         {
1835             foreach (System.Web.Services.Description.Binding binding in wsdlFile.Bindings)
1836             {
1837                 foreach (object extension in binding.Extensions)
1838                 {
1839                     System.Web.Services.Description.HttpBinding httpBinding = extension as System.Web.Services.Description.HttpBinding;
1840                     if (httpBinding != null)
1841                     {
1842                         return true;
1843                     }
1844                 }
1845             }
1846             return false;
1847         }
1848     }
1849 }