/// <summary> /// Check the result from the code generator. /// By default we treat all error messages from WsdlImporter as warnings, /// and they will be ignored if valid code has been generated. /// We may hit other errors when we parse the metadata files. /// Those errors (which are usually because of a bad file) will not be ignored, because the user can fix them. /// If the WsdlImporter hasn't generated any code as we expect, we have to consider some of the error messages are fatal. /// We collect those messages and report to the user. /// </summary> /// <param name="referenceDisplayName">The name of the generated reference</param> /// <param name="mapFile">Original Map File</param> /// <param name="generatedCode">generated code compile unit</param> /// <param name="importErrors"></param> /// <param name="generatorErrors"></param> /// <remarks></remarks> private static void VerifyGeneratedCodeAndHandleErrors( string referenceDisplayName, SvcMapFile mapFile, CodeCompileUnit generatedCode, System.Collections.IEnumerable importErrors, System.Collections.IEnumerable generatorErrors) { // Check and report fatal error first... HandleProxyGenerationErrors(importErrors); HandleProxyGenerationErrors(generatorErrors); // if there is no fatal error, we expect valid type generated from the process // unless there is no metadata files, or there is a service contract type sharing if (mapFile.MetadataList.Count > 0 && mapFile.ClientOptions.ServiceContractMappingList.Count == 0) { if (!IsAnyTypeGenerated(generatedCode)) { StringBuilder collectedMessages = new StringBuilder(); // merge error messages CollectErrorMessages(importErrors, collectedMessages); CollectErrorMessages(generatorErrors, collectedMessages); throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_FailedToGenerateCode, referenceDisplayName, collectedMessages.ToString())); } } }
private CodeCompileUnit GenerateCodeFromServiceMapFile(string mapFilePath) { try { string generatedNamespace = GetGeneratedNamespace(); SvcMapFileLoader loader = new SvcMapFileLoader(mapFilePath); SvcMapFile mapFile = loader.LoadMapFile() as SvcMapFile; HandleProxyGenerationErrors(mapFile.LoadErrors); // We always use C# for the generated proxy CodeDomProvider provider = System.CodeDom.Compiler.CodeDomProvider.CreateProvider("c#"); //Note: with the current implementation of the generator, it does all of its // work in the constructor. This may change in the future. VSWCFServiceContractGenerator generator = VSWCFServiceContractGenerator.GenerateCodeAndConfiguration( mapFile, GetToolConfig(mapFile, mapFilePath), provider, generatedNamespace, null, //targetConfiguration null, //configurationNamespace new ImportExtensionServiceProvider(), new TypeResolver(), FRAMEWORK_VERSION_35, typeof(System.Data.Design.TypedDataSetSchemaImporterExtensionFx35) //Always we are above framework version 3.5 ); // Determine what "name" to display to users for the service if there are any exceptions // If generatedNamespace is empty, then we display the name of the .svcmap file. string referenceDisplayName = String.IsNullOrEmpty(generatedNamespace) ? System.IO.Path.GetFileName(mapFilePath) : generatedNamespace; VerifyGeneratedCodeAndHandleErrors(referenceDisplayName, mapFile, generator.TargetCompileUnit, generator.ImportErrors, generator.ProxyGenerationErrors); #if DEBUG #if false IO.TextWriter writer = new IO.StringWriter(); CodeGeneratorOptions options = new CodeGeneratorOptions(); options.BlankLinesBetweenMembers = true; provider.GenerateCodeFromCompileUnit(generator.TargetCompileUnit, writer, options); Debug.WriteLine("Generated proxy code:\r\n" + writer.ToString()); #endif #endif return(generator.TargetCompileUnit); } catch (Exception ex) { string errorMessage = ex.Message; errorMessage = String.Format(CultureInfo.CurrentCulture, "{0}: {1}", IO.Path.GetFileName(mapFilePath), errorMessage); throw new InvalidOperationException(errorMessage, ex); } }
/// <summary> /// Get the appropriate tool configuration for this service reference. /// /// If a reference.config file is present, the configuration object returned /// will be the merged view of: /// /// Machine Config /// ReferenceConfig /// /// If not reference.config file is present, the configuration object returned /// will be a merged view of: /// /// Machine.config /// web.config in application's physical path... /// /// </summary> /// <param name="mapFile">SvcMapFile representing the service</param> /// <returns></returns> private System.Configuration.Configuration GetToolConfig(SvcMapFile mapFile, string mapFilePath) { string toolConfigFile = null; if (mapFile != null && mapFilePath != null) { foreach (ExtensionFile extensionFile in mapFile.Extensions) { if (String.Equals(extensionFile.Name, TOOL_CONFIG_ITEM_NAME, StringComparison.Ordinal)) { toolConfigFile = extensionFile.FileName; } } } System.Web.Configuration.WebConfigurationFileMap fileMap; fileMap = new System.Web.Configuration.WebConfigurationFileMap(); System.Web.Configuration.VirtualDirectoryMapping mapping; if (toolConfigFile != null) { // // If we've got a specific tool configuration to use, we better load that... // mapping = new System.Web.Configuration.VirtualDirectoryMapping(System.IO.Path.GetDirectoryName(mapFilePath), true, toolConfigFile); } else { // // Otherwise we fall back to the default web.config file... // mapping = new System.Web.Configuration.VirtualDirectoryMapping(HostingEnvironment.ApplicationPhysicalPath, true); } fileMap.VirtualDirectories.Add("/", mapping); return(System.Web.Configuration.WebConfigurationManager.OpenMappedWebConfiguration(fileMap, "/", System.Web.Hosting.HostingEnvironment.SiteName)); }
/// <summary> /// Factory method: generate code and return the resulting VSWCFServiceContractGenerator. /// </summary> /// <param name="svcMapFile"> /// The SvcMapFile that lists the metadata and generation options for the service reference. /// </param> /// <param name="toolConfiguration"> /// Configuration from which we are going to pick up WSDL and policy importer extensions as well /// as custom MEX bindings for metadata download. May be Null/Nothing. /// </param> /// <param name="codeDomProvider"> /// CodeDom provider that is to be used to generate the client code. /// </param> /// <param name="proxyNamespace"> /// CLR namespace in which to generate the client code. /// </param> /// <param name="targetConfiguration"> /// The configuration into which we will put bindings/endpoints for this service /// reference. May be Null/Nothing. /// </param> /// <param name="configurationNamespace"> /// The namespace that is to be used in configuration for this service reference. /// </param> /// <param name="serviceProviderForImportExtensions"> /// Service provider that we'll pass on to import extensions that accept our site:ing /// mechanism /// </param> /// <param name="typeLoader"> /// Type loader that can be used to find reference assemblies and/or resolve shared service and /// data contract types. /// </param> /// <param name="targetFrameworkVersion"> /// The target framework version number. The higher 16 bits contains the major version number, and low 16 bits contains minor version number. /// </param> /// <param name="typedDataSetSchemaImporterExtension"> /// Schema importer extension to be used for typed datasets. /// </param> /// <returns> /// A VSWCFServiceContractGenerator instance that contains the result of the generation. To get /// hold of the generated information, you can query it's properties. /// </returns> public static VSWCFServiceContractGenerator GenerateCodeAndConfiguration(SvcMapFile svcMapFile, System.Configuration.Configuration toolConfiguration, System.CodeDom.Compiler.CodeDomProvider codeDomProvider, string proxyNamespace, System.Configuration.Configuration targetConfiguration, string configurationNamespace, IServiceProvider serviceProviderForImportExtensions, IContractGeneratorReferenceTypeLoader typeLoader, int targetFrameworkVersion, System.Type typedDataSetSchemaImporterExtension) { if (svcMapFile == null) throw new ArgumentNullException("svcMapFile"); if (codeDomProvider == null) throw new ArgumentNullException("codeDomProvider"); if (typedDataSetSchemaImporterExtension == null) throw new ArgumentNullException("typedDataSetSchemaImporterExtension"); List<ProxyGenerationError> importErrors = new List<ProxyGenerationError>(); List<ProxyGenerationError> proxyGenerationErrors = new List<ProxyGenerationError>(); CodeCompileUnit targetCompileUnit = new CodeCompileUnit(); WsdlImporter wsdlImporter = CreateWsdlImporter(svcMapFile, toolConfiguration, targetCompileUnit, codeDomProvider, proxyNamespace, serviceProviderForImportExtensions, typeLoader, targetFrameworkVersion, importErrors, typedDataSetSchemaImporterExtension); ServiceContractGenerator contractGenerator = CreateContractGenerator(svcMapFile.ClientOptions, wsdlImporter, targetCompileUnit, proxyNamespace, targetConfiguration, typeLoader, targetFrameworkVersion, importErrors); try { List<ServiceEndpoint> serviceEndpointList = new List<ServiceEndpoint>(); IEnumerable<System.ServiceModel.Channels.Binding> bindingCollection; IEnumerable<ContractDescription> contractCollection; ImportWCFModel(wsdlImporter, targetCompileUnit, importErrors, out serviceEndpointList, out bindingCollection, out contractCollection); Dictionary<ServiceEndpoint, ChannelEndpointElement> serviceEndpointToChannelEndpointElementMap; List<GeneratedContractType> proxyGeneratedContractTypes; GenerateProxy(wsdlImporter, contractGenerator, targetCompileUnit, proxyNamespace, configurationNamespace, contractCollection, bindingCollection, serviceEndpointList, proxyGenerationErrors, out serviceEndpointToChannelEndpointElementMap, out proxyGeneratedContractTypes); if (IsVBCodeDomProvider(codeDomProvider)) { PatchOutParametersInVB(targetCompileUnit); } return new VSWCFServiceContractGenerator(importErrors, targetCompileUnit, targetConfiguration, bindingCollection, contractCollection, serviceEndpointList, serviceEndpointToChannelEndpointElementMap, proxyGeneratedContractTypes, proxyGenerationErrors); } catch (Exception ex) { // fatal error... (workaround for proxyGenerationErrors.Add(new ProxyGenerationError( ProxyGenerationError.GeneratorState.GenerateCode, String.Empty, ex, false)); return new VSWCFServiceContractGenerator(importErrors, new CodeCompileUnit(), targetConfiguration, new List<System.ServiceModel.Channels.Binding>(), new List<ContractDescription>(), new List<ServiceEndpoint>(), new Dictionary<ServiceEndpoint, ChannelEndpointElement>(), new List<GeneratedContractType>(), proxyGenerationErrors); } }
/// <summary> /// Creates a dictionary containing a copy of the contents of all of the extension files /// </summary> /// <returns></returns> private static Dictionary<string, byte[]> CreateDictionaryOfCopiedExtensionFiles(SvcMapFile svcMapFile) { Dictionary<string, byte[]> extensionFileContents = new Dictionary<string, byte[]>(); foreach (ExtensionFile extensionFile in svcMapFile.Extensions) { // If the extension file was not successfully loaded, do not include it in the // collection. Users are more likely to expect that the extension file won't // be in the collection on an error than they are to assume they have to check // if the byte array we return is null or not. if (extensionFile.ContentBuffer != null && extensionFile.IsBufferValid) { extensionFileContents.Add(extensionFile.Name, (byte[])extensionFile.ContentBuffer.Clone()); } } return extensionFileContents; }
/// <summary> /// Look through all the import extensions to see if any of them want access to /// the service reference's extension files. They tell us this by implementing /// the interface IWcfReferenceReceiveContextInformation. /// </summary> /// <param name="svcMapFile"></param> /// <param name="serviceProviderForImportExtensions"></param> /// <param name="wsdlImportExtensions"></param> /// <param name="policyImportExtensions"></param> internal static void ProvideImportExtensionsWithContextInformation(SvcMapFile svcMapFile, IServiceProvider serviceProviderForImportExtensions, IEnumerable<IWsdlImportExtension> wsdlImportExtensions, IEnumerable<IPolicyImportExtension> policyImportExtensions) { // Only make this copy if we need to (not the mainline case) Dictionary<string, byte[]> extensionFileContents = null; foreach (IWsdlImportExtension wsdlImportExtension in wsdlImportExtensions) { System.Web.Compilation.IWcfReferenceReceiveContextInformation receiveContext = wsdlImportExtension as System.Web.Compilation.IWcfReferenceReceiveContextInformation; if (receiveContext != null) { if (extensionFileContents == null) { extensionFileContents = CreateDictionaryOfCopiedExtensionFiles(svcMapFile); } receiveContext.ReceiveImportContextInformation( extensionFileContents, serviceProviderForImportExtensions); } } foreach (IPolicyImportExtension policyImportExtension in policyImportExtensions) { System.Web.Compilation.IWcfReferenceReceiveContextInformation receiveContext = policyImportExtension as System.Web.Compilation.IWcfReferenceReceiveContextInformation; if (receiveContext != null) { if (extensionFileContents == null) { extensionFileContents = CreateDictionaryOfCopiedExtensionFiles(svcMapFile); } receiveContext.ReceiveImportContextInformation( extensionFileContents, serviceProviderForImportExtensions); } } }
/// <summary> /// Create an appropriate WsdlImporter for the generator /// </summary> /// <param name="svcMapFile"></param> /// <param name="toolConfiguration"></param> /// <param name="targetCompileUnit"></param> /// <param name="codeDomProvider"></param> /// <param name="targetNamespace"></param> /// <param name="typeLoader"></param> /// <param name="targetFrameworkVersion">Targetted Framework version number</param> /// <param name="importErrors"></param> /// <param name="typedDataSetSchemaImporterExtension"></param> /// <returns></returns> protected static WsdlImporter CreateWsdlImporter(SvcMapFile svcMapFile, System.Configuration.Configuration toolConfiguration, CodeCompileUnit targetCompileUnit, System.CodeDom.Compiler.CodeDomProvider codeDomProvider, string targetNamespace, IServiceProvider serviceProviderForImportExtensions, IContractGeneratorReferenceTypeLoader typeLoader, int targetFrameworkVersion, IList<ProxyGenerationError> importErrors, System.Type typedDataSetSchemaImporterExtension) { List<MetadataSection> metadataSections = CollectMetadataDocuments(svcMapFile.MetadataList, importErrors); WsdlImporter importer = null; ClientOptions.ProxySerializerType serializerType = svcMapFile.ClientOptions.Serializer; if (serializerType == ClientOptions.ProxySerializerType.Auto && ContainsHttpBindings(metadataSections)) { // NOTE: HTTP Get/Post binding indicates an old web service. We use XmlSerializer to prevent generating dup classes. // Please check devdiv serializerType = ClientOptions.ProxySerializerType.XmlSerializer; } if (toolConfiguration != null) { ServiceModelSectionGroup serviceModelSection = ServiceModelSectionGroup.GetSectionGroup(toolConfiguration); if (serviceModelSection != null) { Collection<IWsdlImportExtension> wsdlImportExtensions = serviceModelSection.Client.Metadata.LoadWsdlImportExtensions(); Collection<IPolicyImportExtension> policyImportExtensions = serviceModelSection.Client.Metadata.LoadPolicyImportExtensions(); // If we have specified a specific serializer to use, we remove // the other serializer... switch (serializerType) { case ClientOptions.ProxySerializerType.DataContractSerializer: RemoveExtension(typeof(XmlSerializerMessageContractImporter), wsdlImportExtensions); break; case ClientOptions.ProxySerializerType.XmlSerializer: RemoveExtension(typeof(DataContractSerializerMessageContractImporter), wsdlImportExtensions); break; case ClientOptions.ProxySerializerType.Auto: break; default: System.Diagnostics.Debug.Fail("Unknown serializer"); break; } ProvideImportExtensionsWithContextInformation(svcMapFile, serviceProviderForImportExtensions, wsdlImportExtensions, policyImportExtensions); wsdlImportExtensions.Add(new HttpBindingExtension()); // Create Importer... importer = new WsdlImporter(new MetadataSet(metadataSections), policyImportExtensions, wsdlImportExtensions); } } if (importer == null) { importer = new WsdlImporter(new MetadataSet(metadataSections)); } // DevDiv 124333 - Always add DataContract importer (even if we are in XmlSerializerMode) to // enable importing Fault contracts... importer.State.Add(typeof(System.Runtime.Serialization.XsdDataContractImporter), CreateDataContractImporter(svcMapFile.ClientOptions, targetCompileUnit, codeDomProvider, targetNamespace, typeLoader, targetFrameworkVersion, importErrors)); if (serializerType != ClientOptions.ProxySerializerType.DataContractSerializer) { importer.State.Add(typeof(System.ServiceModel.Channels.XmlSerializerImportOptions), CreateXmlSerializerImportOptions(svcMapFile.ClientOptions, targetCompileUnit, codeDomProvider, targetNamespace, typedDataSetSchemaImporterExtension)); } // Read the UseSerializerForFaults from Reference.svcmap, create a FaultImportOptions using this information // and pass it to WSDL Importer. FaultImportOptions faultOptions = new FaultImportOptions(); faultOptions.UseMessageFormat = svcMapFile.ClientOptions.UseSerializerForFaults; importer.State.Add(typeof(System.ServiceModel.FaultImportOptions), faultOptions); // Read the WrappedOptions from Reference.svcmap, create a WrappedOptions using this information // and pass it to WSDL Importer. WrappedOptions wrappedOptions = new WrappedOptions(); wrappedOptions.WrappedFlag = svcMapFile.ClientOptions.Wrapped; importer.State.Add(typeof(System.ServiceModel.Channels.WrappedOptions), wrappedOptions); return importer; }
/// <summary> /// Get the appropriate tool configuration for this service reference. /// /// If a reference.config file is present, the configuration object returned /// will be the merged view of: /// /// Machine Config /// ReferenceConfig /// /// If not reference.config file is present, the configuration object returned /// will be a merged view of: /// /// Machine.config /// web.config in application's physical path... /// /// </summary> /// <param name="mapFile">SvcMapFile representing the service</param> /// <returns></returns> private System.Configuration.Configuration GetToolConfig(SvcMapFile mapFile, string mapFilePath) { string toolConfigFile = null; if (mapFile != null && mapFilePath != null) { foreach (ExtensionFile extensionFile in mapFile.Extensions) { if (String.Equals(extensionFile.Name, TOOL_CONFIG_ITEM_NAME, StringComparison.Ordinal)) { toolConfigFile = extensionFile.FileName; } } } System.Web.Configuration.WebConfigurationFileMap fileMap; fileMap = new System.Web.Configuration.WebConfigurationFileMap(); System.Web.Configuration.VirtualDirectoryMapping mapping; if (toolConfigFile != null) { // // If we've got a specific tool configuration to use, we better load that... // mapping = new System.Web.Configuration.VirtualDirectoryMapping(System.IO.Path.GetDirectoryName(mapFilePath), true, toolConfigFile); } else { // // Otherwise we fall back to the default web.config file... // mapping = new System.Web.Configuration.VirtualDirectoryMapping(HostingEnvironment.ApplicationPhysicalPath, true); } fileMap.VirtualDirectories.Add("/", mapping); return System.Web.Configuration.WebConfigurationManager.OpenMappedWebConfiguration(fileMap, "/", System.Web.Hosting.HostingEnvironment.SiteName); }