/// <summary>
        /// Generates client proxy source code using the specified <paramref name="codeGeneratorName"/> in the context
        /// of the specified <paramref name="host"/>.
        /// </summary>
        /// <param name="host">The host for code generation.</param>
        /// <param name="options">The options to use for code generation.</param>
        /// <param name="assembliesToLoad">The set of server assemblies to use for analysis and composition.</param>
        /// <param name="codeGeneratorName">Optional generator name.  A <c>null</c> or empty value will select the default generator.</param>
        /// <returns>The generated source code or <c>null</c> if none was generated.</returns>
        internal string GenerateCode(ICodeGenerationHost host, ClientCodeGenerationOptions options, IEnumerable <string> assembliesToLoad, string codeGeneratorName)
        {
            Debug.Assert(host != null, "host cannot be null");
            Debug.Assert(options != null, "options cannot be null");
            Debug.Assert(assembliesToLoad != null, "assembliesToLoad cannot be null");

            ILogger logger = host as ILogger;
            DomainServiceCatalog catalog = new DomainServiceCatalog(assembliesToLoad, logger);

            return(this.GenerateCode(host, options, catalog, assembliesToLoad, codeGeneratorName));
        }
        /// <summary>
        /// Generates client proxy source code using the specified <paramref name="codeGeneratorName"/> in the context
        /// of the specified <paramref name="host"/>.
        /// </summary>
        /// <param name="host">The host for code generation.</param>
        /// <param name="options">The options to use for code generation.</param>
        /// <param name="domainServiceTypes">The set of <see cref="OpenRiaServices.DomainServices.Server.DomainService"/> types for which to generate code.</param>
        /// <param name="compositionAssemblies">The optional set of assemblies to use to create the MEF composition container.</param>
        /// <param name="codeGeneratorName">Optional generator name.  A <c>null</c> or empty value will select the default generator.</param>
        /// <returns>The generated source code or <c>null</c> if none was generated.</returns>
        internal string GenerateCode(ICodeGenerationHost host, ClientCodeGenerationOptions options, IEnumerable <Type> domainServiceTypes, IEnumerable <string> compositionAssemblies, string codeGeneratorName)
        {
            Debug.Assert(host != null, "host cannot be null");
            Debug.Assert(options != null, "options cannot be null");
            Debug.Assert(domainServiceTypes != null, "domainServiceTypes cannot be null");

            ILogger logger = host as ILogger;
            DomainServiceCatalog catalog = new DomainServiceCatalog(domainServiceTypes, logger);

            return(this.GenerateCode(host, options, catalog, compositionAssemblies, codeGeneratorName));
        }
        /// <summary>
        /// Generates client proxy source code using the specified <paramref name="codeGeneratorName"/> in the context
        /// of the specified <paramref name="host"/>.
        /// </summary>
        /// <param name="host">The host for code generation.</param>
        /// <param name="options">The options to use for code generation.</param>
        /// <param name="catalog">The catalog containing the <see cref="OpenRiaServices.DomainServices.Server.DomainService"/> types.</param>
        /// <param name="compositionAssemblies">The optional set of assemblies to use to create the MEF composition container.</param>
        /// <param name="codeGeneratorName">Optional generator name.  A <c>null</c> or empty value will select the default generator.</param>
        /// <returns>The generated source code or <c>null</c> if none was generated.</returns>
        private string GenerateCode(ICodeGenerationHost host, ClientCodeGenerationOptions options, DomainServiceCatalog catalog, IEnumerable <string> compositionAssemblies, string codeGeneratorName)
        {
            Debug.Assert(host != null, "host cannot be null");
            Debug.Assert(options != null, "options cannot be null");
            Debug.Assert(catalog != null, "catalog cannot be null");

            IEnumerable <DomainServiceDescription> domainServiceDescriptions = catalog.DomainServiceDescriptions;
            IDomainServiceClientCodeGenerator      proxyGenerator            = this.FindCodeGenerator(host, options, compositionAssemblies, codeGeneratorName);
            string generatedCode = null;

            if (proxyGenerator != null)
            {
                try
                {
                    generatedCode = proxyGenerator.GenerateCode(host, domainServiceDescriptions, options);
                }
                catch (Exception ex)
                {
                    // Fatal exceptions are never swallowed or processed
                    if (ex.IsFatal())
                    {
                        throw;
                    }

                    // Any exception from the code generator is caught and reported, otherwise it will
                    // hit the MSBuild backstop and report failure of the custom build task.
                    // It is acceptable to report this exception and "ignore" it because we
                    // are running in a separate AppDomain which will be torn down immediately
                    // after our return.
                    host.LogError(string.Format(CultureInfo.CurrentCulture,
                                                Resource.CodeGenerator_Threw_Exception,
                                                string.IsNullOrEmpty(codeGeneratorName) ? proxyGenerator.GetType().FullName : codeGeneratorName,
                                                options.ClientProjectPath,
                                                ex.Message));
                }
            }

            return(generatedCode);
        }
        /// <summary>
        /// Validates code gen for a specific language by comparing it against a file containing the expected output.
        /// </summary>
        /// <param name="codeGenOptions">The options specifying the type of validation to perform</param>
        /// <returns>A command that updates the comparison file</returns>
        internal static string ValidateLanguageCodeGen(CodeGenValidationOptions codeGenOptions)
        {
            Assert.IsFalse(string.IsNullOrEmpty(codeGenOptions.Language));

            string outDataDir = TestHelper.GetOutputTestDataDir(codeGenOptions.RelativeDeployDir);
            string extension = TestHelper.ExtensionFromLanguage(codeGenOptions.Language);
            string diffMessage = string.Empty;

            // Compose the abs path to where the test file got deployed by MSTest
            string referenceFileName = TestHelper.GetTestFileName(codeGenOptions.RelativeTestDir, codeGenOptions.BaseReferenceFileName + extension);

            Assert.IsTrue(File.Exists(referenceFileName), "Cannot find reference file " + referenceFileName);
            string generatedCode = string.Empty;

            ClientCodeGenerationOptions options = new ClientCodeGenerationOptions()
            {
                Language = codeGenOptions.Language,
                ClientRootNamespace = codeGenOptions.RootNamespace,
                ClientProjectPath = "MockProject.proj",
                IsApplicationContextGenerationEnabled = codeGenOptions.GenerateApplicationContexts,
                UseFullTypeNames = codeGenOptions.UseFullTypeNames,
                ClientProjectTargetPlatform =  TargetPlatform.Silverlight
            };

            MockCodeGenerationHost host = TestHelper.CreateMockCodeGenerationHost(codeGenOptions.Logger, codeGenOptions.SharedCodeService);
            ILogger logger = host as ILogger;
            DomainServiceCatalog catalog = new DomainServiceCatalog(codeGenOptions.DomainServiceTypes, logger);
            IDomainServiceClientCodeGenerator generator;
            using (ClientCodeGenerationDispatcher dispatcher = new ClientCodeGenerationDispatcher())
            {
                generator = dispatcher.FindCodeGenerator(host, options, /*compositionAssemblies*/ null, /*codeGeneratorName*/ null);
            }
            Assert.IsNotNull(generator, "Failed to find a code generator");
            generatedCode = generator.GenerateCode(host, catalog.DomainServiceDescriptions, options);

            ConsoleLogger consoleLogger = logger as ConsoleLogger;
            string errors = consoleLogger == null ? "" : consoleLogger.Errors;
            Assert.IsTrue(generatedCode.Length > 0, "No code was generated: " + errors);

            // Dump the generated code into a file for comparison
            bool isCSharp = options.Language.Equals("C#", StringComparison.InvariantCultureIgnoreCase);
            string generatedFileName = Path.Combine(outDataDir, Path.GetFileName(referenceFileName) + ".testgen");
            File.WriteAllText(generatedFileName, generatedCode);

            // TODO: (ron M3) Solve inability to get right MSBuild after checkin
            // First see if we compile
            List<string> referenceAssemblies = CompilerHelper.GetSilverlightClientAssemblies(codeGenOptions.RelativeDeployDir);
            List<string> files = new List<string>();

            files.Add(generatedFileName);

            // Unconditionally force generation of Xml doc comments to catch errors
            string documentationFile = Path.GetTempFileName();

            try
            {
                if (isCSharp)
                {
                    files.AddRange(codeGenOptions.SharedFiles.Where(sharedFile => Path.GetExtension(sharedFile).Equals(".cs")));
                    CompilerHelper.CompileCSharpSource(files, referenceAssemblies, documentationFile);
                }
                else
                {
                    files.AddRange(codeGenOptions.SharedFiles.Where(sharedFile => Path.GetExtension(sharedFile).Equals(".vb")));
                    CompilerHelper.CompileVisualBasicSource(files, referenceAssemblies, options.ClientRootNamespace, documentationFile);
                }
            }
            finally
            {
                File.Delete(documentationFile);
            }

            // Do the diff
            if (codeGenOptions.FailOnDiff)
            {
                TestHelper.ValidateFilesEqual(codeGenOptions.RelativeTestDir, codeGenOptions.RelativeDeployDir, generatedFileName, referenceFileName, codeGenOptions.Language);
            }
            else
            {
                TestHelper.FilesMatch(codeGenOptions.RelativeTestDir, codeGenOptions.RelativeDeployDir, generatedFileName, referenceFileName, codeGenOptions.Language, out diffMessage);
            }

            return diffMessage;
        }
 // Invokes the code generator discovered via the host and options
 internal static string GenerateCode(ICodeGenerationHost host, ClientCodeGenerationOptions options, IEnumerable<Type> domainServiceTypes)
 {
     IDomainServiceClientCodeGenerator generator = CreateCodeGenerator(host, options);
     DomainServiceCatalog catalog = new DomainServiceCatalog(domainServiceTypes, host as ILogger);
     return generator.GenerateCode(host, catalog.DomainServiceDescriptions, options);
 }
        /// <summary>
        /// Generates client proxy source code using the specified <paramref name="codeGeneratorName"/> in the context
        /// of the specified <paramref name="host"/>.
        /// </summary>
        /// <param name="host">The host for code generation.</param>
        /// <param name="options">The options to use for code generation.</param>
        /// <param name="catalog">The catalog containing the <see cref="OpenRiaServices.DomainServices.Server.DomainService"/> types.</param>
        /// <param name="compositionAssemblies">The optional set of assemblies to use to create the MEF composition container.</param>
        /// <param name="codeGeneratorName">Optional generator name.  A <c>null</c> or empty value will select the default generator.</param>
        /// <returns>The generated source code or <c>null</c> if none was generated.</returns>
        private string GenerateCode(ICodeGenerationHost host, ClientCodeGenerationOptions options, DomainServiceCatalog catalog, IEnumerable<string> compositionAssemblies, string codeGeneratorName)
        {
            Debug.Assert(host != null, "host cannot be null");
            Debug.Assert(options != null, "options cannot be null");
            Debug.Assert(catalog != null, "catalog cannot be null");

            IEnumerable<DomainServiceDescription> domainServiceDescriptions = catalog.DomainServiceDescriptions;
            IDomainServiceClientCodeGenerator proxyGenerator = this.FindCodeGenerator(host, options, compositionAssemblies, codeGeneratorName);
            string generatedCode = null;

            if (proxyGenerator != null)
            {
                try
                {
                    generatedCode = proxyGenerator.GenerateCode(host, domainServiceDescriptions, options);
                }
                catch (Exception ex)
                {
                    // Fatal exceptions are never swallowed or processed
                    if (ex.IsFatal())
                    {
                        throw;
                    }

                    // Any exception from the code generator is caught and reported, otherwise it will
                    // hit the MSBuild backstop and report failure of the custom build task.
                    // It is acceptable to report this exception and "ignore" it because we
                    // are running in a separate AppDomain which will be torn down immediately
                    // after our return.
                    host.LogError(string.Format(CultureInfo.CurrentCulture, 
                                                    Resource.CodeGenerator_Threw_Exception, 
                                                    string.IsNullOrEmpty(codeGeneratorName) ? proxyGenerator.GetType().FullName : codeGeneratorName,
                                                    options.ClientProjectPath,
                                                    ex.Message));
                }
            }

            return generatedCode;
        }
        /// <summary>
        /// Generates client proxy source code using the specified <paramref name="codeGeneratorName"/> in the context
        /// of the specified <paramref name="host"/>.
        /// </summary>
        /// <param name="host">The host for code generation.</param>
        /// <param name="options">The options to use for code generation.</param>
        /// <param name="domainServiceTypes">The set of <see cref="OpenRiaServices.DomainServices.Server.DomainService"/> types for which to generate code.</param>
        /// <param name="compositionAssemblies">The optional set of assemblies to use to create the MEF composition container.</param>
        /// <param name="codeGeneratorName">Optional generator name.  A <c>null</c> or empty value will select the default generator.</param>
        /// <returns>The generated source code or <c>null</c> if none was generated.</returns>
        internal string GenerateCode(ICodeGenerationHost host, ClientCodeGenerationOptions options, IEnumerable<Type> domainServiceTypes, IEnumerable<string> compositionAssemblies, string codeGeneratorName)
        {
            Debug.Assert(host != null, "host cannot be null");
            Debug.Assert(options != null, "options cannot be null");
            Debug.Assert(domainServiceTypes != null, "domainServiceTypes cannot be null");

            ILogger logger = host as ILogger;
            DomainServiceCatalog catalog = new DomainServiceCatalog(domainServiceTypes, logger);
            return this.GenerateCode(host, options, catalog, compositionAssemblies, codeGeneratorName);
        }
        /// <summary>
        /// Generates client proxy source code using the specified <paramref name="codeGeneratorName"/> in the context
        /// of the specified <paramref name="host"/>.
        /// </summary>
        /// <param name="host">The host for code generation.</param>
        /// <param name="options">The options to use for code generation.</param>
        /// <param name="assembliesToLoad">The set of server assemblies to use for analysis and composition.</param>
        /// <param name="codeGeneratorName">Optional generator name.  A <c>null</c> or empty value will select the default generator.</param>
        /// <returns>The generated source code or <c>null</c> if none was generated.</returns>
        internal string GenerateCode(ICodeGenerationHost host, ClientCodeGenerationOptions options, IEnumerable<string> assembliesToLoad, string codeGeneratorName)
        {
            Debug.Assert(host != null, "host cannot be null");
            Debug.Assert(options != null, "options cannot be null");
            Debug.Assert(assembliesToLoad != null, "assembliesToLoad cannot be null");

            ILogger logger = host as ILogger;
            DomainServiceCatalog catalog = new DomainServiceCatalog(assembliesToLoad, logger);
            return this.GenerateCode(host, options, catalog, assembliesToLoad, codeGeneratorName);
        }