private void Start() { LoadLibrary(HostableWebCoreLocation); _appHostConfigPath = Path.GetTempFileName(); set_main_handler(_hostfxrMainFn); Retry(() => { _currentPort = TestPortHelper.GetNextPort(); InitializeConfig(_currentPort); var startResult = WebCoreActivate(_appHostConfigPath, null, "Instance"); if (startResult != 0) { throw new InvalidOperationException($"Error while running WebCoreActivate: {startResult} on port {_currentPort}"); } }, PortRetryCount); HttpClient = new HttpClient(new LoggingHandler(new SocketsHttpHandler(), _loggerFactory.CreateLogger <TestServer>())) { BaseAddress = BaseUri }; }
public async Task HttpsHelloWorld(TestVariant variant) { var port = TestPortHelper.GetNextSSLPort(); var deploymentParameters = _fixture.GetBaseDeploymentParameters(variant); deploymentParameters.ApplicationBaseUriHint = $"https://localhost:{port}/"; deploymentParameters.AddHttpsToServerConfig(); var deploymentResult = await DeployAsync(deploymentParameters); var handler = new HttpClientHandler { ServerCertificateCustomValidationCallback = (a, b, c, d) => true }; var client = deploymentResult.CreateClient(handler); var response = await client.GetAsync("HttpsHelloWorld"); var responseText = await response.Content.ReadAsStringAsync(); if (variant.HostingModel == HostingModel.OutOfProcess) { Assert.Equal("Scheme:https; Original:http", responseText); } else { Assert.Equal("Scheme:https; Original:", responseText); } }
public Http2TrailerResetTests(IISTestSiteFixture fixture) { var port = TestPortHelper.GetNextSSLPort(); fixture.DeploymentParameters.ApplicationBaseUriHint = $"https://localhost:{port}/"; fixture.DeploymentParameters.AddHttpsToServerConfig(); fixture.DeploymentParameters.SetWindowsAuth(false); Fixture = fixture; }
private IISDeploymentParameters GetHttpsDeploymentParameters() { var port = TestPortHelper.GetNextSSLPort(); var deploymentParameters = Fixture.GetBaseDeploymentParameters(); deploymentParameters.ApplicationBaseUriHint = $"https://localhost:{port}/"; deploymentParameters.AddHttpsToServerConfig(); return(deploymentParameters); }
private async Task ClientCertTest(TestVariant variant, bool sendClientCert) { var port = TestPortHelper.GetNextSSLPort(); var deploymentParameters = Fixture.GetBaseDeploymentParameters(variant); deploymentParameters.ApplicationBaseUriHint = $"https://localhost:{port}/"; deploymentParameters.AddHttpsToServerConfig(); var handler = new HttpClientHandler { ServerCertificateCustomValidationCallback = (a, b, c, d) => true, ClientCertificateOptions = ClientCertificateOption.Manual, }; X509Certificate2 cert = null; if (sendClientCert) { cert = _certFixture.GetOrCreateCertificate(); handler.ClientCertificates.Add(cert); } var deploymentResult = await DeployAsync(deploymentParameters); var client = deploymentResult.CreateClient(handler); var response = await client.GetAsync("GetClientCert"); var responseText = await response.Content.ReadAsStringAsync(); try { if (sendClientCert) { Assert.Equal($"Enabled;{cert.GetCertHashString()}", responseText); } else { Assert.Equal("Disabled", responseText); } } catch (Exception ex) { Logger.LogError($"Certificate is invalid. Issuer name: {cert.Issuer}"); using (var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine)) { Logger.LogError($"List of current certificates in root store:"); store.Open(OpenFlags.ReadWrite); foreach (var otherCert in store.Certificates) { Logger.LogError(otherCert.Issuer); } store.Close(); } throw ex; } }
internal static Uri BuildTestUri(ServerType serverType, string scheme, string hint, bool statusMessagesEnabled) { if (string.IsNullOrEmpty(hint)) { if (serverType == ServerType.Kestrel && statusMessagesEnabled) { // Most functional tests use this codepath and should directly bind to dynamic port "0" and scrape // the assigned port from the status message, which should be 100% reliable since the port is bound // once and never released. Binding to dynamic port "0" on "localhost" (both IPv4 and IPv6) is not // supported, so the port is only bound on "127.0.0.1" (IPv4). If a test explicitly requires IPv6, // it should provide a hint URL with "localhost" (IPv4 and IPv6) or "[::1]" (IPv6-only). return(new UriBuilder(scheme, "127.0.0.1", 0).Uri); } else if (serverType == ServerType.HttpSys) { Debug.Assert(scheme == "http", "Https not supported"); return(new UriBuilder(scheme, "localhost", 0).Uri); } else { // If the server type is not Kestrel, or status messages are disabled, there is no status message // from which to scrape the assigned port, so the less reliable GetNextPort() must be used. The // port is bound on "localhost" (both IPv4 and IPv6), since this is supported when using a specific // (non-zero) port. return(new UriBuilder(scheme, "localhost", TestPortHelper.GetNextPort()).Uri); } } else { var uriHint = new Uri(hint); if (uriHint.Port == 0) { // Only a few tests use this codepath, so it's fine to use the less reliable GetNextPort() for simplicity. // The tests using this codepath will be reviewed to see if they can be changed to directly bind to dynamic // port "0" on "127.0.0.1" and scrape the assigned port from the status message (the default codepath). return(new UriBuilder(uriHint) { Port = TestPortHelper.GetNextPort() }.Uri); } else { // If the hint contains a specific port, return it unchanged. return(uriHint); } } }
public async Task CheckProtocolIsHttp2() { var port = TestPortHelper.GetNextSSLPort(); var deploymentParameters = Fixture.GetBaseDeploymentParameters(HostingModel.InProcess); deploymentParameters.ApplicationBaseUriHint = $"https://localhost:{port}/"; deploymentParameters.AddHttpsToServerConfig(); deploymentParameters.SetWindowsAuth(false); var deploymentResult = await DeployAsync(deploymentParameters); var client = CreateNonValidatingClient(deploymentResult); client.DefaultRequestVersion = HttpVersion.Version20; Assert.Equal("HTTP/2", await client.GetStringAsync($"/CheckProtocol")); }
public async Task HttpsRedirectionWorksIn30AndNot22() { var port = TestPortHelper.GetNextSSLPort(); var deploymentParameters = Fixture.GetBaseDeploymentParameters(HostingModel.OutOfProcess); deploymentParameters.WebConfigBasedEnvironmentVariables["ENABLE_HTTPS_REDIRECTION"] = "true"; deploymentParameters.ApplicationBaseUriHint = $"http://localhost:{TestPortHelper.GetNextPort()}/"; deploymentParameters.AddServerConfigAction( element => { element.Descendants("bindings") .Single() .AddAndGetInnerElement("binding", "protocol", "https") .SetAttributeValue("bindingInformation", $":{port}:localhost"); element.Descendants("access") .Single() .SetAttributeValue("sslFlags", "None"); }); var deploymentResult = await DeployAsync(deploymentParameters); var handler = new HttpClientHandler { ServerCertificateCustomValidationCallback = (a, b, c, d) => true, AllowAutoRedirect = false }; var client = new HttpClient(handler) { BaseAddress = new Uri(deploymentParameters.ApplicationBaseUriHint) }; if (DeployerSelector.HasNewHandler) { var response = await client.GetAsync("/ANCM_HTTPS_PORT"); Assert.Equal(307, (int)response.StatusCode); } else { var response = await client.GetAsync("/ANCM_HTTPS_PORT"); Assert.Equal(200, (int)response.StatusCode); } }
public async Task HttpsPortCanBeOverriden() { var deploymentParameters = _fixture.GetBaseDeploymentParameters(HostingModel.OutOfProcess, publish: true); deploymentParameters.AddServerConfigAction( element => { element.Descendants("bindings") .Single() .GetOrAdd("binding", "protocol", "https") .SetAttributeValue("bindingInformation", $":{TestPortHelper.GetNextSSLPort()}:localhost"); }); deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_HTTPS_PORT"] = "123"; var deploymentResult = await DeployAsync(deploymentParameters); Assert.Equal("123", await deploymentResult.HttpClient.GetStringAsync("/HTTPS_PORT")); }
public async Task ServerAddressesIncludesBaseAddress() { var appName = "\u041C\u043E\u0451\u041F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435"; var port = TestPortHelper.GetNextSSLPort(); var deploymentParameters = _fixture.GetBaseDeploymentParameters(HostingModel.InProcess, publish: true); deploymentParameters.ApplicationBaseUriHint = $"https://localhost:{port}/"; deploymentParameters.AddHttpsToServerConfig(); deploymentParameters.AddServerConfigAction( (element, root) => { element.Descendants("site").Single().Element("application").SetAttributeValue("path", "/" + appName); Helpers.CreateEmptyApplication(element, root); }); var deploymentResult = await DeployAsync(deploymentParameters); Assert.Equal(deploymentParameters.ApplicationBaseUriHint + appName, await deploymentResult.HttpClient.GetStringAsync($"/{appName}/ServerAddresses")); }
public async Task HttpsHelloWorld(TestVariant variant) { var port = TestPortHelper.GetNextSSLPort(); var deploymentParameters = _fixture.GetBaseDeploymentParameters(variant); deploymentParameters.ApplicationBaseUriHint = $"https://localhost:{port}/"; deploymentParameters.AddHttpsToServerConfig(); var deploymentResult = await DeployAsync(deploymentParameters); var handler = new HttpClientHandler { ServerCertificateCustomValidationCallback = (a, b, c, d) => true }; var client = deploymentResult.CreateClient(handler); var response = await client.GetAsync("HttpsHelloWorld"); var responseText = await response.Content.ReadAsStringAsync(); if (variant.HostingModel == HostingModel.OutOfProcess) { Assert.Equal("Scheme:https; Original:http", responseText); } else { Assert.Equal("Scheme:https; Original:", responseText); } if (variant.AncmVersion == AncmVersion.AspNetCoreModuleV2 && DeployerSelector.HasNewHandler && DeployerSelector.HasNewShim) { // We expect ServerAddress to be set for InProcess and HTTPS_PORT for OutOfProcess if (variant.HostingModel == HostingModel.InProcess) { Assert.Equal(deploymentParameters.ApplicationBaseUriHint, await client.GetStringAsync("/ServerAddresses")); } else { Assert.Equal(port.ToString(), await client.GetStringAsync("/HTTPS_PORT")); } } }
private async Task HttpsHelloWorldCerts(TestVariant variant, bool sendClientCert) { var port = TestPortHelper.GetNextSSLPort(); var deploymentParameters = new IISDeploymentParameters(variant) { ApplicationPath = Helpers.GetOutOfProcessTestSitesPath(), ApplicationBaseUriHint = $"https://localhost:{port}/", }; deploymentParameters.AddHttpsToServerConfig(); var deploymentResult = await DeployAsync(deploymentParameters); var handler = new HttpClientHandler { ServerCertificateCustomValidationCallback = (a, b, c, d) => true, ClientCertificateOptions = ClientCertificateOption.Manual }; if (sendClientCert) { X509Certificate2 clientCert = FindClientCert(); Assert.NotNull(clientCert); handler.ClientCertificates.Add(clientCert); } var client = deploymentResult.CreateRetryClient(handler); // Request to base address and check if various parts of the body are rendered & measure the cold startup time. var response = await client.GetAsync("checkclientcert"); var responseText = await response.Content.ReadAsStringAsync(); if (sendClientCert) { Assert.Equal("Scheme:https; Original:http; has cert? True", responseText); } else { Assert.Equal("Scheme:https; Original:http; has cert? False", responseText); } }
public async Task HttpsHelloWorld(TestVariant variant) { var port = TestPortHelper.GetNextSSLPort(); var deploymentParameters = Fixture.GetBaseDeploymentParameters(variant); deploymentParameters.ApplicationBaseUriHint = $"https://localhost:{port}/"; deploymentParameters.AddHttpsToServerConfig(); var deploymentResult = await DeployAsync(deploymentParameters); var client = CreateNonValidatingClient(deploymentResult); var response = await client.GetAsync("HttpsHelloWorld"); var responseText = await response.Content.ReadAsStringAsync(); if (variant.HostingModel == HostingModel.OutOfProcess) { Assert.Equal("Scheme:https; Original:http", responseText); } else { Assert.Equal("Scheme:https; Original:", responseText); } if (DeployerSelector.HasNewHandler && DeployerSelector.HasNewShim) { // We expect ServerAddress to be set for InProcess and ANCM_HTTPS_PORT for OutOfProcess if (variant.HostingModel == HostingModel.InProcess) { Assert.Equal(deploymentParameters.ApplicationBaseUriHint, await client.GetStringAsync("/ServerAddresses")); } else { Assert.Equal(port.ToString(), await client.GetStringAsync("/ANCM_HTTPS_PORT")); } } }
public async Task HttpsHelloWorld(TestVariant variant) { var port = TestPortHelper.GetNextSSLPort(); var deploymentParameters = new DeploymentParameters(variant) { ApplicationPath = Helpers.GetOutOfProcessTestSitesPath(), ApplicationBaseUriHint = $"https://localhost:{port}/", ServerConfigTemplateContent = GetHttpsServerConfig() }; var deploymentResult = await DeployAsync(deploymentParameters); var handler = new HttpClientHandler { ServerCertificateCustomValidationCallback = (a, b, c, d) => true }; var client = deploymentResult.CreateRetryClient(handler); var response = await client.GetAsync("HttpsHelloWorld"); var responseText = await response.Content.ReadAsStringAsync(); Assert.Equal("Scheme:https; Original:http", responseText); }
private async Task <(Uri url, CancellationToken hostExitToken)> StartIISExpressAsync(Uri uri, string contentRoot) { using (Logger.BeginScope("StartIISExpress")) { var port = uri.Port; if (port == 0) { port = (uri.Scheme == "https") ? TestPortHelper.GetNextSSLPort() : TestPortHelper.GetNextPort(); } Logger.LogInformation("Attempting to start IIS Express on port: {port}", port); PrepareConfig(contentRoot, port); var parameters = string.IsNullOrEmpty(DeploymentParameters.ServerConfigLocation) ? string.Format("/port:{0} /path:\"{1}\" /trace:error /systray:false", uri.Port, contentRoot) : string.Format("/site:{0} /config:{1} /trace:error /systray:false", DeploymentParameters.SiteName, DeploymentParameters.ServerConfigLocation); var iisExpressPath = GetIISExpressPath(); for (var attempt = 0; attempt < MaximumAttempts; attempt++) { Logger.LogInformation("Executing command : {iisExpress} {parameters}", iisExpressPath, parameters); var startInfo = new ProcessStartInfo { FileName = iisExpressPath, Arguments = parameters, UseShellExecute = false, CreateNoWindow = true, RedirectStandardError = true, RedirectStandardOutput = true, // VS sets current directory to C:\Program Files\IIS Express WorkingDirectory = Path.GetDirectoryName(iisExpressPath) }; AddEnvironmentVariablesToProcess(startInfo, DeploymentParameters.EnvironmentVariables); Uri url = null; var started = new TaskCompletionSource <bool>(); var process = new Process() { StartInfo = startInfo }; process.OutputDataReceived += (sender, dataArgs) => { if (string.Equals(dataArgs.Data, UnableToStartIISExpressMessage)) { // We completely failed to start and we don't really know why started.TrySetException(new InvalidOperationException("Failed to start IIS Express")); } else if (string.Equals(dataArgs.Data, FailedToInitializeBindingsMessage)) { started.TrySetResult(false); } else if (string.Equals(dataArgs.Data, IISExpressRunningMessage)) { started.TrySetResult(true); } else if (!string.IsNullOrEmpty(dataArgs.Data)) { var m = UrlDetectorRegex.Match(dataArgs.Data); if (m.Success) { url = new Uri(m.Groups["url"].Value); } } }; process.EnableRaisingEvents = true; var hostExitTokenSource = new CancellationTokenSource(); process.Exited += (sender, e) => { Logger.LogInformation("iisexpress Process {pid} shut down", process.Id); // If TrySetResult was called above, this will just silently fail to set the new state, which is what we want started.TrySetException(new Exception($"Command exited unexpectedly with exit code: {process.ExitCode}")); TriggerHostShutdown(hostExitTokenSource); }; process.StartAndCaptureOutAndErrToLogger("iisexpress", Logger); Logger.LogInformation("iisexpress Process {pid} started", process.Id); if (process.HasExited) { Logger.LogError("Host process {processName} {pid} exited with code {exitCode} or failed to start.", startInfo.FileName, process.Id, process.ExitCode); throw new Exception("Failed to start host"); } // Wait for the app to start // The timeout here is large, because we don't know how long the test could need // We cover a lot of error cases above, but I want to make sure we eventually give up and don't hang the build // just in case we missed one -anurse if (!await started.Task.TimeoutAfter(TimeSpan.FromMinutes(10))) { Logger.LogInformation("iisexpress Process {pid} failed to bind to port {port}, trying again", process.Id, port); // Wait for the process to exit and try again process.WaitForExit(30 * 1000); await Task.Delay(1000); // Wait a second to make sure the socket is completely cleaned up } else { _hostProcess = process; // Ensure iisexpress.exe is killed if test process termination is non-graceful. // Prevents locked files when stop debugging unit test. ProcessTracker.Add(_hostProcess); // cache the process start time for verifying log file name. var _ = _hostProcess.StartTime; Logger.LogInformation("Started iisexpress successfully. Process Id : {processId}, Port: {port}", _hostProcess.Id, port); return(url : url, hostExitToken : hostExitTokenSource.Token); } } var message = $"Failed to initialize IIS Express after {MaximumAttempts} attempts to select a port"; Logger.LogError(message); throw new TimeoutException(message); } }
private async Task <(Uri url, CancellationToken hostExitToken)> StartIISExpressAsync(Uri uri, string contentRoot) { using (Logger.BeginScope("StartIISExpress")) { var port = uri.Port; if (port == 0) { port = (uri.Scheme == "https") ? TestPortHelper.GetNextSSLPort() : TestPortHelper.GetNextPort(); } for (var attempt = 0; attempt < MaximumAttempts; attempt++) { Logger.LogInformation("Attempting to start IIS Express on port: {port}", port); if (!string.IsNullOrWhiteSpace(DeploymentParameters.ServerConfigTemplateContent)) { var serverConfig = DeploymentParameters.ServerConfigTemplateContent; // Pass on the applicationhost.config to iis express. With this don't need to pass in the /path /port switches as they are in the applicationHost.config // We take a copy of the original specified applicationHost.Config to prevent modifying the one in the repo. serverConfig = ModifyANCMPathInConfig(replaceFlag: "[ANCMPath]", dllName: "aspnetcore.dll", serverConfig, contentRoot); serverConfig = ModifyANCMPathInConfig(replaceFlag: "[ANCMV2Path]", dllName: "aspnetcorev2.dll", serverConfig, contentRoot); Logger.LogDebug("Writing ApplicationPhysicalPath '{applicationPhysicalPath}' to config", contentRoot); Logger.LogDebug("Writing Port '{port}' to config", port); serverConfig = serverConfig .Replace("[ApplicationPhysicalPath]", contentRoot) .Replace("[PORT]", port.ToString()); DeploymentParameters.ServerConfigLocation = Path.GetTempFileName(); if (serverConfig.Contains("[HostingModel]")) { var hostingModel = DeploymentParameters.HostingModel.ToString(); serverConfig.Replace("[HostingModel]", hostingModel); Logger.LogDebug("Writing HostingModel '{hostingModel}' to config", hostingModel); } Logger.LogDebug("Saving Config to {configPath}", DeploymentParameters.ServerConfigLocation); if (Logger.IsEnabled(LogLevel.Trace)) { Logger.LogTrace($"Config File Content:{Environment.NewLine}===START CONFIG==={Environment.NewLine}{{configContent}}{Environment.NewLine}===END CONFIG===", serverConfig); } File.WriteAllText(DeploymentParameters.ServerConfigLocation, serverConfig); } if (DeploymentParameters.HostingModel == HostingModel.InProcess) { ModifyAspNetCoreSectionInWebConfig(key: "hostingModel", value: "inprocess"); } ModifyHandlerSectionInWebConfig(key: "modules", value: DeploymentParameters.AncmVersion.ToString()); ModifyDotNetExePathInWebConfig(); var parameters = string.IsNullOrWhiteSpace(DeploymentParameters.ServerConfigLocation) ? string.Format("/port:{0} /path:\"{1}\" /trace:error", uri.Port, contentRoot) : string.Format("/site:{0} /config:{1} /trace:error", DeploymentParameters.SiteName, DeploymentParameters.ServerConfigLocation); var iisExpressPath = GetIISExpressPath(); Logger.LogInformation("Executing command : {iisExpress} {parameters}", iisExpressPath, parameters); var startInfo = new ProcessStartInfo { FileName = iisExpressPath, Arguments = parameters, UseShellExecute = false, CreateNoWindow = true, RedirectStandardError = true, RedirectStandardOutput = true }; AddEnvironmentVariablesToProcess(startInfo, DeploymentParameters.EnvironmentVariables); Uri url = null; var started = new TaskCompletionSource <bool>(); var process = new Process() { StartInfo = startInfo }; process.OutputDataReceived += (sender, dataArgs) => { if (string.Equals(dataArgs.Data, UnableToStartIISExpressMessage)) { // We completely failed to start and we don't really know why started.TrySetException(new InvalidOperationException("Failed to start IIS Express")); } else if (string.Equals(dataArgs.Data, FailedToInitializeBindingsMessage)) { started.TrySetResult(false); } else if (string.Equals(dataArgs.Data, IISExpressRunningMessage)) { started.TrySetResult(true); } else if (!string.IsNullOrEmpty(dataArgs.Data)) { var m = UrlDetectorRegex.Match(dataArgs.Data); if (m.Success) { url = new Uri(m.Groups["url"].Value); } } }; process.EnableRaisingEvents = true; var hostExitTokenSource = new CancellationTokenSource(); process.Exited += (sender, e) => { Logger.LogInformation("iisexpress Process {pid} shut down", process.Id); // If TrySetResult was called above, this will just silently fail to set the new state, which is what we want started.TrySetException(new Exception($"Command exited unexpectedly with exit code: {process.ExitCode}")); TriggerHostShutdown(hostExitTokenSource); }; process.StartAndCaptureOutAndErrToLogger("iisexpress", Logger); Logger.LogInformation("iisexpress Process {pid} started", process.Id); if (process.HasExited) { Logger.LogError("Host process {processName} {pid} exited with code {exitCode} or failed to start.", startInfo.FileName, process.Id, process.ExitCode); throw new Exception("Failed to start host"); } // Wait for the app to start // The timeout here is large, because we don't know how long the test could need // We cover a lot of error cases above, but I want to make sure we eventually give up and don't hang the build // just in case we missed one -anurse if (!await started.Task.TimeoutAfter(TimeSpan.FromMinutes(10))) { Logger.LogInformation("iisexpress Process {pid} failed to bind to port {port}, trying again", _hostProcess.Id, port); // Wait for the process to exit and try again process.WaitForExit(30 * 1000); await Task.Delay(1000); // Wait a second to make sure the socket is completely cleaned up } else { _hostProcess = process; Logger.LogInformation("Started iisexpress successfully. Process Id : {processId}, Port: {port}", _hostProcess.Id, port); return(url : url, hostExitToken : hostExitTokenSource.Token); } } var message = $"Failed to initialize IIS Express after {MaximumAttempts} attempts to select a port"; Logger.LogError(message); throw new TimeoutException(message); } }
public WebSocketMiddlewareTests() { ClientPort = TestPortHelper.GetNextPort(); ClientAddress = $"ws://localhost:{ClientPort}/"; }
public override async Task <DeploymentResult> DeployAsync() { using (Logger.BeginScope("Deploy")) { _configFile = Path.GetTempFileName(); var uri = string.IsNullOrEmpty(DeploymentParameters.ApplicationBaseUriHint) ? new Uri("http://localhost:0") : new Uri(DeploymentParameters.ApplicationBaseUriHint); if (uri.Port == 0) { var builder = new UriBuilder(uri); if (OperatingSystem.IsLinux()) { // This works with nginx 1.9.1 and later using the reuseport flag, available on Ubuntu 16.04. // Keep it open so nobody else claims the port _portSelector = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); _portSelector.Bind(new IPEndPoint(IPAddress.Loopback, 0)); builder.Port = ((IPEndPoint)_portSelector.LocalEndPoint).Port; } else { builder.Port = TestPortHelper.GetNextPort(); } uri = builder.Uri; } var redirectUri = TestUriHelper.BuildTestUri(ServerType.Nginx); if (DeploymentParameters.RuntimeFlavor == RuntimeFlavor.CoreClr && DeploymentParameters.ApplicationType == ApplicationType.Standalone) { // Publish is required to get the correct files in the output directory DeploymentParameters.PublishApplicationBeforeDeployment = true; } if (DeploymentParameters.PublishApplicationBeforeDeployment) { DotnetPublish(); } var(appUri, exitToken) = await StartSelfHostAsync(redirectUri); SetupNginx(appUri.ToString(), uri); Logger.LogInformation("Application ready at URL: {appUrl}", uri); // Wait for App to be loaded since Nginx returns 502 instead of 503 when App isn't loaded // Target actual address to avoid going through Nginx proxy using (var httpClient = new HttpClient()) { var response = await RetryHelper.RetryRequest(() => { return(httpClient.GetAsync(redirectUri)); }, Logger, exitToken); if (!response.IsSuccessStatusCode) { throw new InvalidOperationException("Deploy failed"); } } return(new DeploymentResult( LoggerFactory, DeploymentParameters, applicationBaseUri: uri.ToString(), contentRoot: DeploymentParameters.ApplicationPath, hostShutdownToken: exitToken)); } }