diff --git a/src/dotnet-svcutil/lib/src/CommandProcessorOptions.cs b/src/dotnet-svcutil/lib/src/CommandProcessorOptions.cs index 8206ca0572d..05403a36364 100644 --- a/src/dotnet-svcutil/lib/src/CommandProcessorOptions.cs +++ b/src/dotnet-svcutil/lib/src/CommandProcessorOptions.cs @@ -95,6 +95,7 @@ internal class CommandSwitches public readonly CommandSwitch AcceptCertificate = new CommandSwitch(AccecptCertificateKey, "ac", SwitchType.Flag); public readonly CommandSwitch ServiceContract = new CommandSwitch(ServiceContractKey, "sc", SwitchType.Flag); public readonly CommandSwitch Language = new CommandSwitch(LanguageKey, "l", SwitchType.SingletonValue, OperationalContext.Global); + public readonly CommandSwitch SeparateFiles = new CommandSwitch(SeparateFilesKey, "sf", SwitchType.Flag); public void Init() { } // provided as a way to get the static class Switches loaded early. } diff --git a/src/dotnet-svcutil/lib/src/HelpGenerator.cs b/src/dotnet-svcutil/lib/src/HelpGenerator.cs index 38621edebc8..25139b0b372 100644 --- a/src/dotnet-svcutil/lib/src/HelpGenerator.cs +++ b/src/dotnet-svcutil/lib/src/HelpGenerator.cs @@ -72,7 +72,8 @@ private static void WriteCodeGenerationHelp() ArgumentInfo.CreateParameterHelpInfo(CommandProcessorOptions.Switches.TargetFramework.Name, SR.ParametersTargetFramework, string.Format(SR.HelpTargetFrameworkFormat, CommandProcessorOptions.Switches.TargetFramework.Abbreviation)), ArgumentInfo.CreateFlagHelpInfo( CommandProcessorOptions.Switches.AcceptCertificate.Name, string.Format(SR.HelpAcceptCertificateFormat, CommandProcessorOptions.Switches.AcceptCertificate.Abbreviation)), ArgumentInfo.CreateFlagHelpInfo( CommandProcessorOptions.Switches.ServiceContract.Name, string.Format(SR.HelpServiceContractFormat, CommandProcessorOptions.Switches.ServiceContract.Abbreviation)), - ArgumentInfo.CreateFlagHelpInfo( CommandProcessorOptions.Switches.Language.Name, string.Format(SR.HelpLanguage, CommandProcessorOptions.Switches.Language.Abbreviation)) + ArgumentInfo.CreateFlagHelpInfo( CommandProcessorOptions.Switches.Language.Name, string.Format(SR.HelpLanguage, CommandProcessorOptions.Switches.Language.Abbreviation)), + ArgumentInfo.CreateFlagHelpInfo( CommandProcessorOptions.Switches.SeparateFiles.Name, string.Format(SR.HelpSeparateFiles, CommandProcessorOptions.Switches.SeparateFiles.Abbreviation)) } }; diff --git a/src/dotnet-svcutil/lib/src/SR.resx b/src/dotnet-svcutil/lib/src/SR.resx index 4bb86359434..27e58c89aa6 100644 --- a/src/dotnet-svcutil/lib/src/SR.resx +++ b/src/dotnet-svcutil/lib/src/SR.resx @@ -640,4 +640,7 @@ Your credentials will be sent to the server in clear text. The programming language to use for generating code. Examples of language names to use are CS and VB. Default: C#. (Short Form: -{0}) + + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + \ No newline at end of file diff --git a/src/dotnet-svcutil/lib/src/Shared/Options/UpdateOptions.cs b/src/dotnet-svcutil/lib/src/Shared/Options/UpdateOptions.cs index 8fe3eee7ffb..c5183c0bb58 100644 --- a/src/dotnet-svcutil/lib/src/Shared/Options/UpdateOptions.cs +++ b/src/dotnet-svcutil/lib/src/Shared/Options/UpdateOptions.cs @@ -29,6 +29,7 @@ internal partial class UpdateOptions : ApplicationOptions public const string TypeReuseModeKey = "typeReuseMode"; public const string WrappedKey = "wrapped"; public const string LanguageKey = "language"; + public const string SeparateFilesKey = "separateFiles"; #endregion #region properties @@ -49,6 +50,7 @@ internal partial class UpdateOptions : ApplicationOptions public TypeReuseMode? TypeReuseMode { get { return GetValue(TypeReuseModeKey); } set { SetValue(TypeReuseModeKey, value); } } public bool? Wrapped { get { return GetValue(WrappedKey); } set { SetValue(WrappedKey, value); } } public string Language { get { return GetValue(LanguageKey); } set { SetValue(LanguageKey, value); } } + public bool? SeparateFiles { get { return GetValue(SeparateFilesKey); } set { SetValue(SeparateFilesKey, value); } } #endregion public UpdateOptions() @@ -70,7 +72,8 @@ public UpdateOptions() new SingleValueOption(TargetFrameworkKey), new SingleValueOption(TypeReuseModeKey), new SingleValueOption(WrappedKey), - new SingleValueOption(LanguageKey)); + new SingleValueOption(LanguageKey), + new SingleValueOption(SeparateFilesKey) { SerializationName = "separateFiles" }); } public static UpdateOptions FromFile(string filePath, bool throwOnError = true) diff --git a/src/dotnet-svcutil/lib/src/Tool.cs b/src/dotnet-svcutil/lib/src/Tool.cs index 6027a3c43fa..dbf7fe825fa 100644 --- a/src/dotnet-svcutil/lib/src/Tool.cs +++ b/src/dotnet-svcutil/lib/src/Tool.cs @@ -2,8 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.Tools.ServiceModel.Svcutil.Metadata; using System; +using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; @@ -13,6 +13,10 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeDom; +using Microsoft.Tools.ServiceModel.Svcutil.Metadata; +using Newtonsoft.Json.Linq; +using static System.ServiceModel.Channels.RequestReplyCorrelator; using DcNS = System.Runtime.Serialization; namespace Microsoft.Tools.ServiceModel.Svcutil @@ -244,17 +248,75 @@ await serviceDescriptor.ImportMetadataAsync( using (await SafeLogger.WriteStartOperationAsync(options.Logger, "Processing Code DOM ...").ConfigureAwait(false)) { ToolConsole.WriteLine(SR.GeneratingFiles); + if (options.SeparateFiles == true) + { + var originalOutputFile = options.OutputFile; + try + { + var generatedOutputPaths = new HashSet(StringComparer.OrdinalIgnoreCase); + foreach (CodeNamespace @namespace in importModule.CodeCompileUnit.Namespaces) + { + foreach (CodeTypeDeclaration type in @namespace.Types) + { + var namespacePrefix = GetSafeNamespaceFilePrefix(@namespace.Name); + var outputFileName = $"{namespacePrefix}.{type.Name}{CodeSerializer.GetOutputFileExtension(options)}"; + var outputPath = Path.Combine(options.OutputDir.FullName, outputFileName); + if (!generatedOutputPaths.Add(outputPath)) + { + throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, + "A generated output file collision was detected for type '{0}' in namespace '{1}'. The file path '{2}' is already assigned to another generated type.", + type.Name, @namespace.Name, outputPath)); + } + options.OutputFile = new FileInfo(outputPath); + CodeSerializer codeSerializer = new CodeSerializer(options, serviceDescriptor.MetadataDocuments); + CodeCompileUnit compileUnit = new CodeCompileUnit(); + CodeNamespace splitNamespace = new CodeNamespace(@namespace.Name); + + // Transfer the assembly attributes, referenced assemblies, user data and directives to each split compile unit to ensure the generated code is correct. + compileUnit.AssemblyCustomAttributes.AddRange(importModule.CodeCompileUnit.AssemblyCustomAttributes); + compileUnit.StartDirectives.AddRange(importModule.CodeCompileUnit.StartDirectives); + compileUnit.EndDirectives.AddRange(importModule.CodeCompileUnit.EndDirectives); + compileUnit.ReferencedAssemblies.AddRange(importModule.CodeCompileUnit.ReferencedAssemblies.Cast().ToArray()); + foreach (DictionaryEntry pair in importModule.CodeCompileUnit.UserData) + { + compileUnit.UserData.Add(pair.Key, pair.Value); + } + + compileUnit.Namespaces.Add(splitNamespace); + splitNamespace.Types.Add(type); + var filePath = codeSerializer.Save(compileUnit); + ToolConsole.WriteLineIf(options.ToolContext != OperationalContext.Infrastructure, filePath, LogTag.Important); + } + } + } + finally + { + options.OutputFile = originalOutputFile; + } + } + else + { + CodeSerializer codeSerializer = new CodeSerializer(options, serviceDescriptor.MetadataDocuments); + var filePath = codeSerializer.Save(importModule.CodeCompileUnit); - CodeSerializer codeSerializer = new CodeSerializer(options, serviceDescriptor.MetadataDocuments); - var filePath = codeSerializer.Save(importModule.CodeCompileUnit); - - // When in Infrastructure mode (WCF CS) it is assumed the output file path have been provided so no need to display it. - ToolConsole.WriteLineIf(options.ToolContext != OperationalContext.Infrastructure, filePath, LogTag.Important); + // When in Infrastructure mode (WCF CS) it is assumed the output file path have been provided so no need to display it. + ToolConsole.WriteLineIf(options.ToolContext != OperationalContext.Infrastructure, filePath, LogTag.Important); + } } return ToolConsole.ExitCode; } + private static string GetSafeNamespaceFilePrefix(string namespaceName) + { + var prefix = string.IsNullOrWhiteSpace(namespaceName) ? "Global" : namespaceName; + foreach (var invalidChar in Path.GetInvalidFileNameChars()) + { + prefix = prefix.Replace(invalidChar, '_'); + } + return prefix.Replace('.', '_'); + } + private static bool IsSuccess(int result) { return result == (int)ToolExitCode.Success || result == (int)ToolExitCode.ValidationErrorTurnedWarning; diff --git a/src/dotnet-svcutil/lib/src/xlf/SR.cs.xlf b/src/dotnet-svcutil/lib/src/xlf/SR.cs.xlf index 2d0e81a727f..3400553e826 100644 --- a/src/dotnet-svcutil/lib/src/xlf/SR.cs.xlf +++ b/src/dotnet-svcutil/lib/src/xlf/SR.cs.xlf @@ -617,6 +617,11 @@ Identifikátor dokumentu: {0} Vygenerovat kód pro kontrakty služeb Třída klienta se nevygeneruje. (Krátký tvar: -{0}) + + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + + Generate synchronous methods for operations in addition to async. (Short Form: -{0}) Kromě asynchronních metod generovat pro operace i synchronní metody (krátký tvar: -{0}) @@ -878,4 +883,4 @@ Vaše přihlašovací údaje se odešlou na server v podobě prostého textu. - \ No newline at end of file + diff --git a/src/dotnet-svcutil/lib/src/xlf/SR.de.xlf b/src/dotnet-svcutil/lib/src/xlf/SR.de.xlf index c050f793868..591a8463a1d 100644 --- a/src/dotnet-svcutil/lib/src/xlf/SR.de.xlf +++ b/src/dotnet-svcutil/lib/src/xlf/SR.de.xlf @@ -617,6 +617,11 @@ Dokumentbezeichner: "{0}". Generieren Sie Code für Dienstleistungsverträge. Die Clientklasse wird nicht generiert. (Kurzform: -{0}) + + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + + Generate synchronous methods for operations in addition to async. (Short Form: -{0}) Hiermit werden synchrone Methoden für Vorgänge generiert, die zusätzlich zu asynchronen Vorgängen ausgeführt werden. (Kurzform: -{0}) @@ -878,4 +883,4 @@ Die Anmeldeinformationen werden in Klartext an den Server gesendet. - \ No newline at end of file + diff --git a/src/dotnet-svcutil/lib/src/xlf/SR.es.xlf b/src/dotnet-svcutil/lib/src/xlf/SR.es.xlf index b4bbc991109..329b52f021b 100644 --- a/src/dotnet-svcutil/lib/src/xlf/SR.es.xlf +++ b/src/dotnet-svcutil/lib/src/xlf/SR.es.xlf @@ -617,6 +617,11 @@ Identificador del documento: "{0}". Generar código para Service Contracts. La clase cliente no se generará. (Forma corta: {0}) + + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + + Generate synchronous methods for operations in addition to async. (Short Form: -{0}) Genere métodos sincrónicos para las operaciones además de los asincrónicos. (Forma corta: -{0}) @@ -878,4 +883,4 @@ Las credenciales se enviarán al servidor en texto no cifrado. - \ No newline at end of file + diff --git a/src/dotnet-svcutil/lib/src/xlf/SR.fr.xlf b/src/dotnet-svcutil/lib/src/xlf/SR.fr.xlf index c6217db1f8a..d18bd67909b 100644 --- a/src/dotnet-svcutil/lib/src/xlf/SR.fr.xlf +++ b/src/dotnet-svcutil/lib/src/xlf/SR.fr.xlf @@ -617,6 +617,11 @@ Identificateur de document : '{0}'. Générez du code pour les contrats de service. La classe cliente ne sera pas générée. (Forme abrégée : -{0}) + + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + + Generate synchronous methods for operations in addition to async. (Short Form: -{0}) Générez des méthodes synchrones pour les opérations en plus des méthodes asynchrones. (Forme abrégée : -{0}) @@ -878,4 +883,4 @@ Vos informations d'identification vont être envoyées au serveur en texte clair - \ No newline at end of file + diff --git a/src/dotnet-svcutil/lib/src/xlf/SR.it.xlf b/src/dotnet-svcutil/lib/src/xlf/SR.it.xlf index 8c039dfba9a..63a2765e9d3 100644 --- a/src/dotnet-svcutil/lib/src/xlf/SR.it.xlf +++ b/src/dotnet-svcutil/lib/src/xlf/SR.it.xlf @@ -617,6 +617,11 @@ Identificatore di documento: '{0}'. Generare il codice per i contratti di servizio. La classe client non verrà generata. (Forma breve: -{0}) + + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + + Generate synchronous methods for operations in addition to async. (Short Form: -{0}) Genera metodi sincroni per le operazioni oltre a quelli asincroni. Forma breve: -{0} @@ -878,4 +883,4 @@ Le credenziali verranno inviate al server come testo non crittografato. - \ No newline at end of file + diff --git a/src/dotnet-svcutil/lib/src/xlf/SR.ja.xlf b/src/dotnet-svcutil/lib/src/xlf/SR.ja.xlf index 0e83c3b8ca5..5106a0414bb 100644 --- a/src/dotnet-svcutil/lib/src/xlf/SR.ja.xlf +++ b/src/dotnet-svcutil/lib/src/xlf/SR.ja.xlf @@ -617,6 +617,11 @@ Document Identifier: '{0}'. サービス コントラクトのコードを生成します。クライアント クラスは生成されません。(短い形式: -{0}) + + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + + Generate synchronous methods for operations in addition to async. (Short Form: -{0}) 非同期のものに加えて、操作の同期メソッドを生成します。(短縮形: -{0}) @@ -878,4 +883,4 @@ Your credentials will be sent to the server in clear text. - \ No newline at end of file + diff --git a/src/dotnet-svcutil/lib/src/xlf/SR.ko.xlf b/src/dotnet-svcutil/lib/src/xlf/SR.ko.xlf index df79c3b67ce..f09399ff27a 100644 --- a/src/dotnet-svcutil/lib/src/xlf/SR.ko.xlf +++ b/src/dotnet-svcutil/lib/src/xlf/SR.ko.xlf @@ -617,6 +617,11 @@ Document Identifier: '{0}'. 서비스 계약에 대한 코드를 생성합니다. 클라이언트 클래스는 생성되지 않습니다. (약식: -{0}) + + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + + Generate synchronous methods for operations in addition to async. (Short Form: -{0}) 비동기 외에 작업에 대한 동기 메서드를 생성합니다. (약식: -{0}) @@ -878,4 +883,4 @@ Your credentials will be sent to the server in clear text. - \ No newline at end of file + diff --git a/src/dotnet-svcutil/lib/src/xlf/SR.pl.xlf b/src/dotnet-svcutil/lib/src/xlf/SR.pl.xlf index f761c161994..916b475ea4b 100644 --- a/src/dotnet-svcutil/lib/src/xlf/SR.pl.xlf +++ b/src/dotnet-svcutil/lib/src/xlf/SR.pl.xlf @@ -617,6 +617,11 @@ Identyfikator dokumentu: „{0}”. Generuj kod dla kontraktów usług. Klasa klienta nie zostanie wygenerowana. (Krótka wersja: —{0}) + + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + + Generate synchronous methods for operations in addition to async. (Short Form: -{0}) Generuj metody synchroniczne dla operacji, oprócz metod asynchronicznych. (Krótka forma: -{0}) @@ -878,4 +883,4 @@ Twoje poświadczenia zostaną wysłane do serwera jako zwykły tekst. - \ No newline at end of file + diff --git a/src/dotnet-svcutil/lib/src/xlf/SR.pt-BR.xlf b/src/dotnet-svcutil/lib/src/xlf/SR.pt-BR.xlf index 01a14cfc559..f7b5b1622c3 100644 --- a/src/dotnet-svcutil/lib/src/xlf/SR.pt-BR.xlf +++ b/src/dotnet-svcutil/lib/src/xlf/SR.pt-BR.xlf @@ -617,6 +617,11 @@ Identificador do Documento: '{0}'. Gerar código para Contratos de Serviço. A classe de cliente não será gerada. (Forma resumida: -{0}) + + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + + Generate synchronous methods for operations in addition to async. (Short Form: -{0}) Gere métodos síncronos para operações, além de assíncronos. (Forma Abreviada: -{0}) @@ -878,4 +883,4 @@ As credenciais serão enviadas para o servidor em texto não criptografado. - \ No newline at end of file + diff --git a/src/dotnet-svcutil/lib/src/xlf/SR.ru.xlf b/src/dotnet-svcutil/lib/src/xlf/SR.ru.xlf index 8b35a8f61d5..5934e39d0c6 100644 --- a/src/dotnet-svcutil/lib/src/xlf/SR.ru.xlf +++ b/src/dotnet-svcutil/lib/src/xlf/SR.ru.xlf @@ -617,6 +617,11 @@ Document Identifier: '{0}'. Создание кода для контрактов на предоставление услуг. Класс клиента не будет создан. (Короткая форма: -{0}) + + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + + Generate synchronous methods for operations in addition to async. (Short Form: -{0}) Создавать синхронные методы для операций в дополнение к асинхронным. (Краткая форма: -{0}) @@ -878,4 +883,4 @@ Your credentials will be sent to the server in clear text. - \ No newline at end of file + diff --git a/src/dotnet-svcutil/lib/src/xlf/SR.tr.xlf b/src/dotnet-svcutil/lib/src/xlf/SR.tr.xlf index 4e7fff2fd33..39872b07cd9 100644 --- a/src/dotnet-svcutil/lib/src/xlf/SR.tr.xlf +++ b/src/dotnet-svcutil/lib/src/xlf/SR.tr.xlf @@ -617,6 +617,11 @@ Belge Tanımlayıcısı: '{0}'. Hizmet Sözleşmeleri için kod oluşturun. İstemci sınıfı oluşturulmaz. (Kısa Biçim: -{0}) + + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + + Generate synchronous methods for operations in addition to async. (Short Form: -{0}) İşlemler için zaman uyumsuz yöntemlerin yanı sıra zaman uyumlu yöntemler oluştur. (Kısa Biçim: -{0}) @@ -878,4 +883,4 @@ Kimlik bilgileriniz sunucuya düz metin olarak gönderilecek. - \ No newline at end of file + diff --git a/src/dotnet-svcutil/lib/src/xlf/SR.zh-Hans.xlf b/src/dotnet-svcutil/lib/src/xlf/SR.zh-Hans.xlf index 1cdfb2d92f4..8663cfd89df 100644 --- a/src/dotnet-svcutil/lib/src/xlf/SR.zh-Hans.xlf +++ b/src/dotnet-svcutil/lib/src/xlf/SR.zh-Hans.xlf @@ -617,6 +617,11 @@ Document Identifier: '{0}'. 为服务协定生成代码。将不会生成客户端类。(缩写: -{0}) + + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + + Generate synchronous methods for operations in addition to async. (Short Form: -{0}) 为除异步以外的操作生成同步方法。(缩写: -{0}) @@ -878,4 +883,4 @@ Your credentials will be sent to the server in clear text. - \ No newline at end of file + diff --git a/src/dotnet-svcutil/lib/src/xlf/SR.zh-Hant.xlf b/src/dotnet-svcutil/lib/src/xlf/SR.zh-Hant.xlf index 5603b618e15..f524240e36d 100644 --- a/src/dotnet-svcutil/lib/src/xlf/SR.zh-Hant.xlf +++ b/src/dotnet-svcutil/lib/src/xlf/SR.zh-Hant.xlf @@ -617,6 +617,11 @@ Document Identifier: '{0}'. 產生服務合約的程式碼。將不會產生用戶端類別。(簡短形式: -{0}) + + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + Creates separate files for each type in the specified output directory. (Short Form: -{0}) + + Generate synchronous methods for operations in addition to async. (Short Form: -{0}) 除了非同步方法外,也會為作業產生同步方法。(簡短形式: -{0}) @@ -878,4 +883,4 @@ Your credentials will be sent to the server in clear text. - \ No newline at end of file +