/// <summary> /// Runs 'dotnet run' on the specified project while only exposing a HTTP endpoint. /// </summary> /// <param name="project">The project.</param> /// <param name="projectRelativeDirectoryPath">The project relative directory path.</param> /// <param name="action">The action to perform while the project is running.</param> /// <param name="noRestore">Whether to restore the project.</param> /// <param name="validateCertificate">Validate the project certificate.</param> /// <param name="timeout">The timeout.</param> /// <returns>A task representing the operation.</returns> public static async Task DotnetRunAsync( this Project project, string projectRelativeDirectoryPath, Func <HttpClient, Task> action, bool?noRestore = true, Func <HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> validateCertificate = null, TimeSpan?timeout = null) { if (project == null) { throw new ArgumentNullException(nameof(project)); } if (projectRelativeDirectoryPath == null) { throw new ArgumentNullException(nameof(projectRelativeDirectoryPath)); } if (action == null) { throw new ArgumentNullException(nameof(action)); } var httpPort = PortHelper.GetFreeTcpPort(); var httpUrl = $"http://localhost:{httpPort}"; var projectFilePath = Path.Combine(project.DirectoryPath, projectRelativeDirectoryPath); var dotnetRun = await DotnetRunInternalAsync(projectFilePath, noRestore, timeout, httpUrl).ConfigureAwait(false); var httpClientHandler = new HttpClientHandler() { AllowAutoRedirect = false, ServerCertificateCustomValidationCallback = validateCertificate ?? DefaultValidateCertificate, }; var httpClient = new HttpClient(httpClientHandler) { BaseAddress = new Uri(httpUrl) }; try { await action(httpClient).ConfigureAwait(false); } finally { httpClient.Dispose(); httpClientHandler.Dispose(); dotnetRun.Dispose(); } }