/// <summary>
        /// Tries to loads the OpenRiaServices.DomainServices.Server assembly from the server projects references.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        /// <param name="loggingService">The logging service.</param>
        private static void LoadOpenRiaServicesServerAssembly(SharedCodeServiceParameters parameters, ILoggingService loggingService)
        {
            // Try to load the OpenRiaServices.DomainServies.Server assembly using the one used by the server project
            // This way we can be sure that codegen works with both signed and unsigned server assembly while
            // making sure that only a single version is loaded
            var filename           = OpenRiaServices_DomainServices_Server_Assembly;
            var serverAssemblyPath = parameters.ServerAssemblies.FirstOrDefault(sa => sa.EndsWith(filename));

            if (serverAssemblyPath != null)
            {
                var serverAssembly = AssemblyUtilities.LoadAssembly(serverAssemblyPath, loggingService);
                if (serverAssembly != null)
                {
                    // Since this assembly (OpenRiaServices.DomainServices.Tools) requires the Server assembly to be loaded
                    // before the final call to AssemblyUtilities.SetAssemblyResolver (when the DomainServiceCatalog is instanciated)
                    // we need to setup our assembly resolver with the server assembly in case the server version is signed
                    // but this version is unsigned
                    if (!serverAssembly.GetName().IsSigned())
                    {
                        loggingService.LogWarning(Resource.ClientCodeGen_SignedTools_UnsignedServer);
                    }
                }
                else
                {
                    loggingService.LogError(string.Format(CultureInfo.CurrentCulture,
                                                          Resource.ClientCodeGen_Failed_Loading_OpenRiaServices_Assembly, filename, serverAssemblyPath));
                }
            }
            else
            {
                loggingService.LogError(string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Missing_OpenRiaServices_Reference, filename));
            }
        }
        /// <summary>
        /// Generates client proxy source code using the generator specified by <paramref name="codeGeneratorName"/>.
        /// </summary>
        /// <param name="options">The options to use for code generation.</param>
        /// <param name="parameters">The parameters required to create the <see cref="ISharedCodeService"/>.</param>
        /// <param name="loggingService">The service to use for logging.</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(ClientCodeGenerationOptions options, SharedCodeServiceParameters parameters, ILoggingService loggingService, string codeGeneratorName)
        {
            Debug.Assert(options != null, "options cannot be null");
            Debug.Assert(parameters != null, "parameters cannot be null");
            Debug.Assert(loggingService != null, "loggingService cannot be null");

            try
            {
                AppDomainUtilities.ConfigureAppDomain(options);
                LoadOpenRiaServicesServerAssembly(parameters, loggingService);

                using (SharedCodeService sharedCodeService = new SharedCodeService(parameters, loggingService))
                {
                    CodeGenerationHost host = new CodeGenerationHost(loggingService, sharedCodeService);
                    return(this.GenerateCode(host, options, parameters.ServerAssemblies, codeGeneratorName));
                }
            }
            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.
                loggingService.LogError(string.Format(CultureInfo.CurrentCulture,
                                                      Resource.ClientCodeGenDispatecher_Threw_Exception_Before_Generate,
                                                      ex.Message));
                loggingService.LogException(ex);
                return(null);
            }
        }
        /// <summary>
        /// Generates client proxy source code using the generator specified by <paramref name="codeGeneratorName"/>.
        /// </summary>
        /// <param name="options">The options to use for code generation.</param>
        /// <param name="parameters">The parameters required to create the <see cref="ISharedCodeService"/>.</param>
        /// <param name="loggingService">The service to use for logging.</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(ClientCodeGenerationOptions options, SharedCodeServiceParameters parameters, ILoggingService loggingService, string codeGeneratorName)
        {
            Debug.Assert(options != null, "options cannot be null");
            Debug.Assert(parameters != null, "parameters cannot be null");
            Debug.Assert(loggingService != null, "loggingService cannot be null");

            try
            {
                AppDomainUtilities.ConfigureAppDomain(options);
                LoadOpenRiaServicesServerAssembly(parameters, loggingService);

                using (SharedCodeService sharedCodeService = new SharedCodeService(parameters, loggingService))
                {
                    CodeGenerationHost host = new CodeGenerationHost(loggingService, sharedCodeService);
                    return this.GenerateCode(host, options, parameters.ServerAssemblies, codeGeneratorName);
                }
            }
            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.
                loggingService.LogError(string.Format(CultureInfo.CurrentCulture,
                                                Resource.ClientCodeGenDispatecher_Threw_Exception_Before_Generate,
                                                ex.Message));
                loggingService.LogException(ex);
                return null;
            }
        }
        /// <summary>
        /// Constructs the parameters to pass across the AppDomain boundary to construct a
        /// <see cref="SharedCodeService"/> in the AppDomain that will do code generation.
        /// </summary>
        /// <param name="serverAssemblies">The set of full paths to the server assemblies to use for code generation.</param>
        /// <returns>A <see cref="SharedCodeServiceParameters"/> instance ready to use to construct a <see cref="SharedCodeService"/>.</returns>
        private SharedCodeServiceParameters CreateSharedCodeServiceParameters(IEnumerable<string> serverAssemblies)
        {
            SharedCodeServiceParameters parameters = new SharedCodeServiceParameters();

            parameters.ServerAssemblies = serverAssemblies.ToArray();

            // Get all *.shared.* and linked files in common between client and server.
            // These are consider "shared files" by the shared type service
            parameters.SharedSourceFiles = this.GetSharedAndLinkedFiles().ToArray();

            // Present the list of shared files to the user as a informational level log
            if (parameters.SharedSourceFiles.Any())
            {
                StringBuilder sb = new StringBuilder();
                foreach (string file in parameters.SharedSourceFiles)
                {
                    sb.AppendLine();
                    sb.Append("    " + file);
                }
                this.LogMessage(string.Format(CultureInfo.CurrentCulture, Resource.CodeGen_Shared_Files, sb.ToString()));
            }

            parameters.ClientAssemblies = this.NormalizedTaskItems(this.ClientReferenceAssemblies, this.ClientProjectDirectory).ToArray();
            parameters.ClientAssemblyPathsNormalized = this.ClientAssemblyPathsNormalized.ToArray();

            // Convert the list of server assemblies into a search path for PDB's
            parameters.SymbolSearchPaths = serverAssemblies.Select(a => Path.GetDirectoryName(a)).ToArray();

            return parameters;
        }
        /// <summary>
        /// Tries to loads the OpenRiaServices.DomainServices.Server assembly from the server projects references.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        /// <param name="loggingService">The logging service.</param>
        private static void LoadOpenRiaServicesServerAssembly(SharedCodeServiceParameters parameters, ILoggingService loggingService)
        {
            // Try to load the OpenRiaServices.DomainServies.Server assembly using the one used by the server project
            // This way we can be sure that codegen works with both signed and unsigned server assembly while
            // making sure that only a single version is loaded
            var filename = OpenRiaServices_DomainServices_Server_Assembly;
            var serverAssemblyPath = parameters.ServerAssemblies.FirstOrDefault(sa => sa.EndsWith(filename));
            if (serverAssemblyPath != null)
            {
                var serverAssembly = AssemblyUtilities.LoadAssembly(serverAssemblyPath, loggingService);
                if (serverAssembly != null)
                {
                    // Since this assembly (OpenRiaServices.DomainServices.Tools) requires the Server assembly to be loaded
                    // before the final call to AssemblyUtilities.SetAssemblyResolver (when the DomainServiceCatalog is instanciated)
                    // we need to setup our assembly resolver with the server assembly in case the server version is signed
                    // but this version is unsigned
#if SIGNED
                    if (!serverAssembly.GetName().IsSigned())
                    {
                        loggingService.LogWarning(Resource.ClientCodeGen_SignedTools_UnsignedServer);
                    }
#else
                    AssemblyUtilities.SetAssemblyResolver(new[] { serverAssembly });
#endif
                }
                else
                {
                    loggingService.LogError(string.Format(CultureInfo.CurrentCulture,
                        Resource.ClientCodeGen_Failed_Loading_OpenRiaServices_Assembly, filename, serverAssemblyPath));
                }

            }
            else
            {
                loggingService.LogError(string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Missing_OpenRiaServices_Reference, filename));
            }
        }