private void PublishWithDotnetExe(string framework)
        {
            var projectFile = Path.Combine(SourceApplicationsDirectoryPath, ApplicationDirectoryName,
                                           ApplicationDirectoryName + ".csproj");
            var deployPath = Path.Combine(DestinationRootDirectoryPath, ApplicationDirectoryName);

            TestLogger?.WriteLine($"[RemoteService]: Publishing to {deployPath}.");

            var process   = new Process();
            var startInfo = new ProcessStartInfo();

            startInfo.WindowStyle            = ProcessWindowStyle.Hidden;
            startInfo.UseShellExecute        = false;
            startInfo.FileName               = "dotnet.exe";
            startInfo.RedirectStandardOutput = true;
            startInfo.RedirectStandardError  = true;

            startInfo.Arguments =
                $"publish {projectFile} --configuration Release --runtime win-x64 --framework {framework} --output {deployPath}";
            process.StartInfo = startInfo;

            //We cannot run dotnet publish against the same directory concurrently.
            //Doing so causes the publish job to fail because it can't obtain a lock on files in the obj and bin directories.
            lock (GetPublishLockObjectForCoreApp())
            {
                process.Start();

                var processOutput = new ProcessOutput(TestLogger, process, true);

                const int timeoutInMilliseconds = 3 * 60 * 1000;
                if (!process.WaitForExit(timeoutInMilliseconds))
                {
                    TestLogger?.WriteLine($"[RemoteService]: PublishCoreApp timed out while waiting for {ApplicationDirectoryName} to publish after {timeoutInMilliseconds} milliseconds.");
                    try
                    {
                        //This usually happens because another publishing job has a lock on the file(s) being copied.
                        //We send a termination request because we no longer want dotnet publish to continue to copy files
                        //when there's a good chance that at least some of the files are missing.
                        //We can only use "kill" to request termination here, because there isn't a "close" option for non-GUI apps.
                        process.Kill();
                    }
                    catch (Exception e)
                    {
                        TestLogger?.WriteLine($"======[RemoteService]: PublishCoreApp failed to kill process that publishes {ApplicationDirectoryName} with exception =====");
                        TestLogger?.WriteLine(e.ToString());
                        TestLogger?.WriteLine($"-----[RemoteService]: PublishCoreApp failed to kill process that publishes {ApplicationDirectoryName} end of exception -----");
                    }
                }
                else
                {
                    Console.WriteLine($"[{DateTime.Now}] dotnet.exe exits with code {process.ExitCode}");
                }

                processOutput.WriteProcessOutputToLog("[RemoteService]: PublishCoreApp");

                if (!process.HasExited || process.ExitCode != 0)
                {
                    var failedToPublishMessage = "Failed to publish Core application";

                    TestLogger?.WriteLine($"[RemoteService]: {failedToPublishMessage}");
                    throw new Exception(failedToPublishMessage);
                }
            }

            Console.WriteLine($"[{DateTime.Now}] Successfully published {projectFile} to {deployPath}");
        }
        public override void Start(string commandLineArguments, bool captureStandardOutput = false, bool doProfile = true)
        {
            var arguments = UsesSpecificPort
                ? $"--port={Port} {commandLineArguments}"
                : commandLineArguments;

            var applicationFilePath       = DestinationApplicationExecutablePath;
            var profilerFilePath          = Path.Combine(DestinationNewRelicHomeDirectoryPath, @"NewRelic.Profiler.dll");
            var newRelicHomeDirectoryPath = DestinationNewRelicHomeDirectoryPath;
            var profilerLogDirectoryPath  = Path.Combine(DestinationNewRelicHomeDirectoryPath, @"Logs");

            var startInfo = new ProcessStartInfo
            {
                Arguments              = arguments,
                FileName               = applicationFilePath,
                UseShellExecute        = false,
                WorkingDirectory       = DestinationApplicationDirectoryPath,
                RedirectStandardOutput = captureStandardOutput,
                RedirectStandardError  = captureStandardOutput,
                RedirectStandardInput  = RedirectStandardInput
            };

            startInfo.EnvironmentVariables.Remove("COR_ENABLE_PROFILING");
            startInfo.EnvironmentVariables.Remove("COR_PROFILER");
            startInfo.EnvironmentVariables.Remove("COR_PROFILER_PATH");
            startInfo.EnvironmentVariables.Remove("NEWRELIC_HOME");
            startInfo.EnvironmentVariables.Remove("NEWRELIC_PROFILER_LOG_DIRECTORY");
            startInfo.EnvironmentVariables.Remove("NEWRELIC_LICENSEKEY");
            startInfo.EnvironmentVariables.Remove("NEW_RELIC_LICENSE_KEY");
            startInfo.EnvironmentVariables.Remove("NEW_RELIC_HOST");

            startInfo.EnvironmentVariables.Remove("CORECLR_ENABLE_PROFILING");
            startInfo.EnvironmentVariables.Remove("CORECLR_PROFILER");
            startInfo.EnvironmentVariables.Remove("CORECLR_PROFILER_PATH");
            startInfo.EnvironmentVariables.Remove("CORECLR_NEWRELIC_HOME");

            if (!doProfile)
            {
                startInfo.EnvironmentVariables.Add("CORECLR_ENABLE_PROFILING", "0");
            }
            else if (IsCoreApp)
            {
                startInfo.EnvironmentVariables.Add("CORECLR_ENABLE_PROFILING", "1");
                startInfo.EnvironmentVariables.Add("CORECLR_PROFILER", "{36032161-FFC0-4B61-B559-F6C5D41BAE5A}");
                startInfo.EnvironmentVariables.Add("CORECLR_PROFILER_PATH", profilerFilePath);
                startInfo.EnvironmentVariables.Add("CORECLR_NEWRELIC_HOME", newRelicHomeDirectoryPath);

                if (UseTieredCompilation)
                {
                    startInfo.EnvironmentVariables.Add("COMPlus_TieredCompilation", "1");
                }
            }
            else
            {
                startInfo.EnvironmentVariables.Add("COR_ENABLE_PROFILING", "1");
                startInfo.EnvironmentVariables.Add("COR_PROFILER", "{71DA0A04-7777-4EC6-9643-7D28B46A8A41}");
                startInfo.EnvironmentVariables.Add("COR_PROFILER_PATH", profilerFilePath);
                startInfo.EnvironmentVariables.Add("NEWRELIC_HOME", newRelicHomeDirectoryPath);
            }

            if (AdditionalEnvironmentVariables != null)
            {
                foreach (var kp in AdditionalEnvironmentVariables)
                {
                    startInfo.EnvironmentVariables.Add(kp.Key, kp.Value);
                }
            }

            startInfo.EnvironmentVariables.Add("NEWRELIC_PROFILER_LOG_DIRECTORY", profilerLogDirectoryPath);

            RemoteProcess           = new Process();
            RemoteProcess.StartInfo = startInfo;
            RemoteProcess.Start();

            if (RemoteProcess == null)
            {
                throw new Exception("Process failed to start.");
            }

            CapturedOutput = new ProcessOutput(TestLogger, RemoteProcess, captureStandardOutput);

            if (RemoteProcess.HasExited && RemoteProcess.ExitCode != 0)
            {
                if (captureStandardOutput)
                {
                    CapturedOutput.WriteProcessOutputToLog("[RemoteService]: Start");
                }
                throw new Exception("App server shutdown unexpectedly.");
            }

            WaitForAppServerToStartListening(RemoteProcess, captureStandardOutput);
        }