| File: Microsoft\Tools\ServiceModel\SvcUtil\XmlSerializerGenerator.cs | Web Access |
| Project: src\src\svcutilcore\src\dotnet-svcutil.xmlserializer.csproj (dotnet-svcutil.xmlserializer) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. namespace Microsoft.Tools.ServiceModel.SvcUtil.XmlSerializer { using System; using System.Reflection; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Globalization; using System.Text; using System.Xml.Serialization; using System.CodeDom.Compiler; internal class XmlSerializerGenerator : OutputModule { private const string sourceExtension = ".cs"; private readonly ExportModule.IsTypeExcludedDelegate _isTypeExcluded; private string _outFile; internal XmlSerializerGenerator(Options options) : base(options) { _isTypeExcluded = options.IsTypeExcluded; _outFile = options.OutputFileArg; } internal void GenerateCode(List<Assembly> assemblies) { if (!string.IsNullOrEmpty(_outFile) && assemblies.Count > 1) { ToolConsole.WriteWarning(SR.Format(SR.WrnOptionConflictsWithInput, Options.Cmd.Out)); _outFile = null; } foreach (Assembly assembly in assemblies) { GenerateCode(assembly); } } private void GenerateCode(Assembly assembly) { List<XmlMapping> mappings = new List<XmlMapping>(); List<Type> types = CollectXmlSerializerTypes(assembly, mappings); #pragma warning disable SYSLIB0044 if (types.Count == 0) { ToolConsole.WriteWarning(SR.Format(SR.WrnNoServiceContractTypes, assembly.GetName().CodeBase)); return; } if (mappings.Count == 0) { ToolConsole.WriteWarning(SR.Format(SR.WrnNoXmlSerializerOperationBehavior, assembly.GetName().CodeBase)); return; } #pragma warning restore SYSLIB0044 bool success = false; bool toDeleteFile = true; string codePath = Path.GetTempFileName(); try { if (File.Exists(codePath)) { File.Delete(codePath); } using (FileStream fs = File.Create(codePath)) { MethodInfo method = typeof(System.Xml.Serialization.XmlSerializer).GetMethod("GenerateSerializer", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { throw new ToolRuntimeException(SR.GenerateSerializerNotFound); } else { success = (bool)method.Invoke(null, new object[] { types.ToArray(), mappings.ToArray(), fs }); } } } finally { if (!success && toDeleteFile && File.Exists(codePath)) { File.Delete(codePath); } } string sgenSource = XmlSerializer.GetXmlSerializerAssemblyName(types[0]); // delete all temp files generated by CodeDom except source file sgenSource = BuildFilePath(sgenSource, sourceExtension, null); if (File.Exists(sgenSource)) File.Delete(sgenSource); string sourceName; if (_outFile != null) sourceName = FilenameHelper.UniquifyFileName(_outFile, sourceExtension); else sourceName = FilenameHelper.UniquifyFileName(sgenSource, sourceExtension); string sourceFilePath = BuildFilePath(sourceName, sourceExtension, null); CreateDirectoryIfNeeded(sourceFilePath); File.Copy(codePath, sourceFilePath, true); ToolConsole.WriteLine(sourceFilePath); return; } private List<Type> CollectXmlSerializerTypes(Assembly assembly, List<XmlMapping> mappings) { List<Type> types = new List<Type>(); ExportModule.ContractLoader contractLoader = new ExportModule.ContractLoader(new Assembly[] { assembly }, _isTypeExcluded); contractLoader.ContractLoadErrorCallback = delegate (Type contractType, string errorMessage) { ToolConsole.WriteWarning(SR.Format(SR.WrnUnableToLoadContractForSGen, contractType, errorMessage)); }; Type contractDescriptionType = Tool.SMAssembly.GetType("System.ServiceModel.Description.ContractDescription"); if (contractDescriptionType == null) { ToolConsole.WriteError($"Not found type System.ServiceModel.Description.ContractDescription in {Tool.SMAssembly.FullName}"); throw new ToolRuntimeException(); } PropertyInfo contractTypeProperty = contractDescriptionType.GetProperty("ContractType"); if (contractTypeProperty == null) { ToolConsole.WriteError($"Not found property ContractType in type {contractDescriptionType}"); throw new ToolRuntimeException(); } Type xmlSerializerOperationBehaviorType = Tool.SMAssembly.GetType("System.ServiceModel.Description.XmlSerializerOperationBehavior"); if (xmlSerializerOperationBehaviorType == null) { ToolConsole.WriteError($"Not found type System.ServiceModel.Description.XmlSerializerOperationBehaviorType in {Tool.SMAssembly.FullName}"); throw new ToolRuntimeException(); } Type operationType = Tool.SMAssembly.GetType("System.ServiceModel.Description.OperationDescription"); if (operationType == null) { ToolConsole.WriteError($"Not found type System.ServiceModel.Description.OperationDescription in {Tool.SMAssembly.FullName}"); throw new ToolRuntimeException(); } PropertyInfo getBehaviorsProperty = operationType.GetProperty("Behaviors"); if (getBehaviorsProperty == null) { ToolConsole.WriteError($"Not found method get_Behaviors in type {operationType}"); throw new ToolRuntimeException(); } Type keyedByTypeCollectionType = Tool.SMAssembly.GetType("System.Collections.Generic.KeyedByTypeCollection`1"); if (keyedByTypeCollectionType == null) { ToolConsole.WriteError($"Not found type System.Collections.Generic.KeyedByTypeCollection`1 in {Tool.SMAssembly.FullName}"); throw new ToolRuntimeException(); } Type iOperationBehaviorType = Tool.SMAssembly.GetType("System.ServiceModel.Description.IOperationBehavior"); if (iOperationBehaviorType == null) { ToolConsole.WriteError($"Not found type System.ServiceModel.Description.IOperationBehavior in {Tool.SMAssembly.FullName}"); throw new ToolRuntimeException(); } keyedByTypeCollectionType = keyedByTypeCollectionType.MakeGenericType(new Type[] { iOperationBehaviorType }); if (keyedByTypeCollectionType == null) { ToolConsole.WriteError($"Cannot make Generic Type System.Collections.Generic.KeyedByTypeCollection<IOperationBehavior> in {Tool.SMAssembly.FullName}"); throw new ToolRuntimeException(); } MethodInfo findMethod = keyedByTypeCollectionType.GetMethod("Find"); if(findMethod == null) { ToolConsole.WriteError($"Not found method find in type {keyedByTypeCollectionType}"); throw new ToolRuntimeException(); } findMethod = findMethod.MakeGenericMethod(new Type[] { xmlSerializerOperationBehaviorType }); if (findMethod == null) { ToolConsole.WriteError($"Not found method Find<XmlSerializerOperationBehavior> in operation.Behaviors"); throw new ToolRuntimeException(); } MethodInfo getXmlMappingsMethod = xmlSerializerOperationBehaviorType.GetMethod("GetXmlMappings"); if (getXmlMappingsMethod == null) { ToolConsole.WriteError($"Not found method getXmlMappings in XmlSerializerOperationBehavior"); throw new ToolRuntimeException(); } PropertyInfo operationsProperty = contractDescriptionType.GetProperty("Operations"); if (operationsProperty == null) { ToolConsole.WriteError($"Not found property Operations in type {contractDescriptionType}"); throw new ToolRuntimeException(); } //Use reflection to replace the following code //foreach (ContractDescription contract in contractLoader.GetContracts()) //{ // types.Add(contract.ContractType); // foreach (OperationDescription operation in contract.Operations) // { // XmlSerializerOperationBehavior behavior = operation.Behaviors.Find<XmlSerializerOperationBehavior>(); // if (behavior != null) // { // foreach (XmlMapping map in behavior.GetXmlMappings()) // { // mappings.Add(map); // } // } // } //} foreach (object contract in contractLoader.GetContracts()) { types.Add((Type)contractTypeProperty.GetValue(contract)); System.Collections.IEnumerable operations = (System.Collections.IEnumerable)operationsProperty.GetValue(contract); foreach(var operation in operations) { if(operation == null) { throw new ToolRuntimeException("operation is null"); } var behaviors = getBehaviorsProperty.GetValue(operation); var behavior = findMethod.Invoke(behaviors, new object[] { }); if (behavior != null) { var xmlMappings = (Collection<XmlMapping>)getXmlMappingsMethod.Invoke(behavior, new object[] { }); if (xmlMappings != null) { foreach (XmlMapping map in xmlMappings) { mappings.Add(map); } } } } } return types; } } }