public void Start(string hostId, Action<int> onConnected) { lock (_processLock) { if (_stopped) { return; } int port = GetFreePort(); var psi = new ProcessStartInfo { FileName = _paths.Dnx ?? _paths.Klr, CreateNoWindow = true, UseShellExecute = false, RedirectStandardError = true, Arguments = string.Format(@"""{0}"" {1} {2} {3}", Path.Combine(_paths.RuntimePath.Value, "bin", "lib", "Microsoft.Framework.DesignTimeHost", "Microsoft.Framework.DesignTimeHost.dll"), port, Process.GetCurrentProcess().Id, hostId), }; #if DNX451 psi.EnvironmentVariables["KRE_APPBASE"] = Directory.GetCurrentDirectory(); psi.EnvironmentVariables["DNX_APPBASE"] = Directory.GetCurrentDirectory(); #else psi.Environment["KRE_APPBASE"] = Directory.GetCurrentDirectory(); psi.Environment["DNX_APPBASE"] = Directory.GetCurrentDirectory(); #endif _logger.LogVerbose(psi.FileName + " " + psi.Arguments); _designTimeHostProcess = Process.Start(psi); // Wait a little bit for it to conncet before firing the callback using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) { var t1 = DateTime.UtcNow; var dthTimeout = TimeSpan.FromSeconds(4); while (!socket.Connected && DateTime.UtcNow - t1 < dthTimeout) { Thread.Sleep(500); try { socket.Connect(new IPEndPoint(IPAddress.Loopback, port)); } catch (SocketException) { // this happens when the DTH isn't listening yet } } } if (_designTimeHostProcess.HasExited) { // REVIEW: Should we quit here or retry? _logger.LogError(string.Format("Failed to launch DesignTimeHost. Process exited with code {0}.", _designTimeHostProcess.ExitCode)); return; } _logger.LogInformation(string.Format("Running DesignTimeHost on port {0}, with PID {1}", port, _designTimeHostProcess.Id)); _designTimeHostProcess.EnableRaisingEvents = true; _designTimeHostProcess.OnExit(() => { _logger.LogWarning("Design time host process ended"); Start(hostId, onConnected); }); onConnected(port); } }
public void Start(string hostId, Action<int> onConnected) { lock (_processLock) { if (_stopped) { return; } int port = GetFreePort(); string runtimePath = _paths.RuntimePath.Value; // This gets the folder name (e.g. dnx-mono.1.0.0-beta5 or dnx-clr-x86.1.0.0-beta5) var fullName = DnxSdk.GetRuntimeNameFromFullPath(runtimePath); string flavor; string os; string arch; string version; if (DnxSdk.TryParseFullName(fullName, out flavor, out os, out arch, out version) && string.Equals(flavor, "coreclr", StringComparison.OrdinalIgnoreCase) && !string.Equals(os, "win", StringComparison.OrdinalIgnoreCase)) { // Work around since DTH is broken on CoreCLR on *nix and OSX var runtimeName = DnxSdk.GetFullName(version, "mono", os, arch); runtimePath = Path.Combine(Path.GetDirectoryName(runtimePath), runtimeName); _logger.LogInformation("Using '{0}' for design time host.", runtimePath); } var dthPath = Path.Combine(runtimePath, "bin", "lib", "Microsoft.Dnx.DesignTimeHost", "Microsoft.Dnx.DesignTimeHost.dll"); // TODO: This is for backcompat. Once the dust settles, and MS.Framework.DTH goes away, remove this. if (!File.Exists(dthPath)) { dthPath = Path.Combine(runtimePath, "bin", "lib", "Microsoft.Framework.DesignTimeHost", "Microsoft.Framework.DesignTimeHost.dll"); } var dnx = DnxPaths.FirstPath(runtimePath, "dnx", "dnx.exe"); var klr = DnxPaths.FirstPath(runtimePath, "klr", "klr.exe"); var psi = new ProcessStartInfo { FileName = dnx ?? klr, CreateNoWindow = true, UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, Arguments = string.Format(@"""{0}"" {1} {2} {3}", dthPath, port, Process.GetCurrentProcess().Id, hostId), }; #if DNX451 psi.EnvironmentVariables["KRE_APPBASE"] = Directory.GetCurrentDirectory(); psi.EnvironmentVariables["DNX_APPBASE"] = Directory.GetCurrentDirectory(); #else psi.Environment["KRE_APPBASE"] = Directory.GetCurrentDirectory(); psi.Environment["DNX_APPBASE"] = Directory.GetCurrentDirectory(); #endif _logger.LogDebug(psi.FileName + " " + psi.Arguments); _designTimeHostProcess = new Process(); _designTimeHostProcess.StartInfo = psi; _designTimeHostProcess.OutputDataReceived += (sender, args) => this._logger.LogInformation(args.Data ?? string.Empty); this._designTimeHostProcess.Start(); this._designTimeHostProcess.BeginOutputReadLine(); // Wait a little bit for it to conncet before firing the callback using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) { var t1 = DateTime.UtcNow; var dthTimeout = TimeSpan.FromSeconds(30); while (!socket.Connected && DateTime.UtcNow - t1 < dthTimeout) { Thread.Sleep(500); try { socket.Connect(new IPEndPoint(IPAddress.Loopback, port)); } catch (SocketException) { // this happens when the DTH isn't listening yet } } if (!socket.Connected) { // reached timeout _logger.LogError("Failed to launch DesignTimeHost in a timely fashion."); return; } } if (_designTimeHostProcess.HasExited) { // REVIEW: Should we quit here or retry? _logger.LogError(string.Format("Failed to launch DesignTimeHost. Process exited with code {0}.", _designTimeHostProcess.ExitCode)); return; } _logger.LogInformation(string.Format("Running DesignTimeHost on port {0}, with PID {1}", port, _designTimeHostProcess.Id)); _designTimeHostProcess.EnableRaisingEvents = true; _designTimeHostProcess.OnExit(() => { _logger.LogWarning("Design time host process ended"); Start(hostId, onConnected); }); onConnected(port); } }