internal async Task <ProcessResult> RunDotNetEfUpdateDatabaseAsync() { var assembly = typeof(ProjectFactoryFixture).Assembly; var args = "--verbose --no-build database update"; // Only run one instance of 'dotnet new' at once, as a workaround for // https://github.com/aspnet/templating/issues/63 await DotNetNewLock.WaitAsync(); try { Output.WriteLine("Acquired DotNetNewLock"); var command = DotNetMuxer.MuxerPathOrDefault(); if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("DotNetEfFullPath"))) { args = $"\"{DotNetEfFullPath}\" " + args; } else { command = "dotnet-ef"; } using var result = ProcessEx.Run(Output, TemplateOutputDir, command, args); await result.Exited; return(new ProcessResult(result)); } finally { DotNetNewLock.Release(); Output.WriteLine("Released DotNetNewLock"); } }
internal async Task <ProcessEx> RunDotNetEfUpdateDatabaseAsync() { var assembly = typeof(ProjectFactoryFixture).Assembly; var dotNetEfFullPath = assembly.GetCustomAttributes <AssemblyMetadataAttribute>() .First(attribute => attribute.Key == "DotNetEfFullPath") .Value; var args = $"\"{dotNetEfFullPath}\" --verbose --no-build database update"; // Only run one instance of 'dotnet new' at once, as a workaround for // https://github.com/aspnet/templating/issues/63 await DotNetNewLock.WaitAsync(); try { var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), args); await result.Exited; return(result); } finally { DotNetNewLock.Release(); } }
internal async Task <ProcessEx> RunDotNetEfCreateMigrationAsync(string migrationName) { var args = $"--verbose --no-build migrations add {migrationName}"; // Only run one instance of 'dotnet new' at once, as a workaround for // https://github.com/aspnet/templating/issues/63 await DotNetNewLock.WaitAsync(); try { var command = DotNetMuxer.MuxerPathOrDefault(); if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("DotNetEfFullPath"))) { args = $"\"{DotNetEfFullPath}\" " + args; } else { command = "dotnet-ef"; } var result = ProcessEx.Run(Output, TemplateOutputDir, command, args); await result.Exited; return(result); } finally { DotNetNewLock.Release(); } }
internal async Task <ProcessEx> RunDotNetPublishAsync(bool takeNodeLock = false) { Output.WriteLine("Publishing ASP.NET application..."); // Workaround for issue with runtime store not yet being published // https://github.com/aspnet/Home/issues/2254#issuecomment-339709628 var extraArgs = "-p:PublishWithAspNetCoreTargetManifest=false"; // This is going to trigger a build, so we need to acquire the lock like in the other cases. // We want to take the node lock as some builds run NPM as part of the build and we want to make sure // it's run without interruptions. var effectiveLock = takeNodeLock ? new OrderedLock(NodeLock, DotNetNewLock) : new OrderedLock(nodeLock: null, DotNetNewLock); await effectiveLock.WaitAsync(); try { var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), $"publish -c Release {extraArgs}"); await result.Exited; return(result); } finally { effectiveLock.Release(); } }
public AspNetProcess( ITestOutputHelper output, string workingDirectory, string dllPath, IDictionary <string, string> environmentVariables, bool published = true, bool hasListeningUri = true) { _output = output; _httpClient = new HttpClient(new HttpClientHandler() { AllowAutoRedirect = true, UseCookies = true, CookieContainer = new CookieContainer(), ServerCertificateCustomValidationCallback = (m, c, ch, p) => true, }) { Timeout = TimeSpan.FromMinutes(2) }; var now = DateTimeOffset.Now; new CertificateManager().EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1)); output.WriteLine("Running ASP.NET application..."); var arguments = published ? $"exec {dllPath}" : "run"; Process = ProcessEx.Run(output, workingDirectory, DotNetMuxer.MuxerPathOrDefault(), arguments, envVars: environmentVariables); if (hasListeningUri) { ListeningUri = GetListeningUri(output); } }
private static void VerifyCannotFindTemplate(ITestOutputHelper output, string templateName) { // Verify we really did remove the previous templates var tempDir = Path.Combine(AppContext.BaseDirectory, Path.GetRandomFileName(), Guid.NewGuid().ToString("D")); Directory.CreateDirectory(tempDir); try { var proc = ProcessEx.Run( output, tempDir, DotNetMuxer.MuxerPathOrDefault(), $"new \"{templateName}\""); proc.WaitForExit(assertSuccess: false); if (!proc.Error.Contains($"No templates matched the input template name: {templateName}.")) { throw new InvalidOperationException($"Failed to uninstall previous templates. The template '{templateName}' could still be found."); } } finally { Directory.Delete(tempDir, recursive: true); } }
public static void ReinstallTemplatePackages() { // Remove any previous or prebundled version of the template packages foreach (var packageName in _templatePackages) { var proc = ProcessEx.Run( Directory.GetCurrentDirectory(), "dotnet", $"new --uninstall {packageName}"); proc.WaitForExit(assertSuccess: true); } VerifyCannotFindTemplate("ASP.NET Core Empty"); // Locate the artifacts directory containing the built template packages var solutionDir = FindAncestorDirectoryContaining("Templating.sln"); var artifactsDir = Path.Combine(solutionDir, "artifacts"); var builtPackages = Directory.GetFiles(artifactsDir, "*.nupkg"); foreach (var packagePath in builtPackages) { if (_templatePackages.Any(name => Path.GetFileName(packagePath).StartsWith(name, StringComparison.OrdinalIgnoreCase))) { Console.WriteLine($"Installing templates package {packagePath}..."); var proc = ProcessEx.Run( Directory.GetCurrentDirectory(), "dotnet", $"new --install \"{packagePath}\""); proc.WaitForExit(assertSuccess: true); } } }
public AspNetProcess( ITestOutputHelper output, string workingDirectory, string dllPath, IDictionary <string, string> environmentVariables, bool published = true, bool hasListeningUri = true) { _output = output; _httpClient = new HttpClient(new HttpClientHandler() { AllowAutoRedirect = true, UseCookies = true, CookieContainer = new CookieContainer(), ServerCertificateCustomValidationCallback = (m, c, ch, p) => true, }) { Timeout = TimeSpan.FromMinutes(2) }; EnsureDevelopmentCertificates(); output.WriteLine("Running ASP.NET application..."); var arguments = published ? $"exec {dllPath}" : "run"; Process = ProcessEx.Run(output, workingDirectory, DotNetMuxer.MuxerPathOrDefault(), arguments, envVars: environmentVariables); if (hasListeningUri) { ListeningUri = GetListeningUri(output) ?? throw new InvalidOperationException("Couldn't find the listening URL."); } }
public AspNetProcess(ITestOutputHelper output, string workingDirectory, string projectName, bool publish) { _output = output; _httpClient = new HttpClient(new HttpClientHandler() { AllowAutoRedirect = true, UseCookies = true, CookieContainer = new CookieContainer(), ServerCertificateCustomValidationCallback = (m, c, ch, p) => true }); var now = DateTimeOffset.Now; new CertificateManager().EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1)); if (publish) { output.WriteLine("Publishing ASP.NET application..."); // Workaround for issue with runtime store not yet being published // https://github.com/aspnet/Home/issues/2254#issuecomment-339709628 var extraArgs = "-p:PublishWithAspNetCoreTargetManifest=false"; ProcessEx .Run(output, workingDirectory, DotNetMuxer.MuxerPathOrDefault(), $"publish -c Release {extraArgs}") .WaitForExit(assertSuccess: true); workingDirectory = Path.Combine(workingDirectory, "bin", "Release", DefaultFramework, "publish"); if (File.Exists(Path.Combine(workingDirectory, "ClientApp", "package.json"))) { Npm.RestoreWithRetry(output, Path.Combine(workingDirectory, "ClientApp")); } } else { output.WriteLine("Building ASP.NET application..."); ProcessEx .Run(output, workingDirectory, DotNetMuxer.MuxerPathOrDefault(), "build -c Debug") .WaitForExit(assertSuccess: true); } var envVars = new Dictionary <string, string> { { "ASPNETCORE_URLS", $"http://127.0.0.1:0;https://127.0.0.1:0" } }; if (!publish) { envVars["ASPNETCORE_ENVIRONMENT"] = "Development"; } output.WriteLine("Running ASP.NET application..."); var dllPath = publish ? $"{projectName}.dll" : $"bin/Debug/{DefaultFramework}/{projectName}.dll"; _process = ProcessEx.Run(output, workingDirectory, DotNetMuxer.MuxerPathOrDefault(), $"exec {dllPath}", envVars: envVars); _listeningUri = GetListeningUri(output); }
internal async Task <ProcessEx> RunDotNetNewAsync(string templateName, string auth = null, string language = null, bool useLocalDB = false, bool noHttps = false, string[] args = null) { var hiveArg = $"--debug:custom-hive \"{TemplatePackageInstaller.CustomHivePath}\""; var argString = $"new {templateName} {hiveArg}"; if (!string.IsNullOrEmpty(auth)) { argString += $" --auth {auth}"; } if (!string.IsNullOrEmpty(language)) { argString += $" -lang {language}"; } if (useLocalDB) { argString += $" --use-local-db"; } if (noHttps) { argString += $" --no-https"; } if (args != null) { foreach (var arg in args) { argString += " " + arg; } } // Save a copy of the arguments used for better diagnostic error messages later. // We omit the hive argument and the template output dir as they are not relevant and add noise. ProjectArguments = argString.Replace(hiveArg, ""); argString += $" -o {TemplateOutputDir}"; // Only run one instance of 'dotnet new' at once, as a workaround for // https://github.com/aspnet/templating/issues/63 await DotNetNewLock.WaitAsync(); try { var execution = ProcessEx.Run(Output, AppContext.BaseDirectory, DotNetMuxer.MuxerPathOrDefault(), argString); await execution.Exited; return(execution); } finally { DotNetNewLock.Release(); } }
public static async Task <ProcessEx> RunDotNetNew(ITestOutputHelper output, string arguments) { var proc = ProcessEx.Run( output, AppContext.BaseDirectory, DotNetMuxer.MuxerPathOrDefault(), $"new {arguments} --debug:custom-hive \"{CustomHivePath}\""); await proc.Exited; return(proc); }
internal async Task <ProcessResult> RunDotNetBuildAsync(IDictionary <string, string> packageOptions = null, string additionalArgs = null) { Output.WriteLine("Building ASP.NET Core application..."); // Avoid restoring as part of build or publish. These projects should have already restored as part of running dotnet new. Explicitly disabling restore // should avoid any global contention and we can execute a build or publish in a lock-free way using var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), $"build --no-restore -c Debug /bl {additionalArgs}", packageOptions); await result.Exited; CaptureBinLogOnFailure(result); return(new ProcessResult(result)); }
public static ProcessEx RunDotNetNew(ITestOutputHelper output, string arguments, bool assertSuccess) { lock (DotNetNewLock) { var proc = ProcessEx.Run( output, AppContext.BaseDirectory, DotNetMuxer.MuxerPathOrDefault(), $"new {arguments} --debug:custom-hive \"{CustomHivePath}\""); proc.WaitForExit(assertSuccess); return(proc); } }
public static async Task <ProcessEx> RunDotNetNew(ITestOutputHelper output, string arguments) { var proc = ProcessEx.Run( output, AppContext.BaseDirectory, DotNetMuxer.MuxerPathOrDefault(), //--debug:disable-sdk-templates means, don't include C:\Program Files\dotnet\templates, aka. what comes with SDK, so we don't need to uninstall //--debug:custom-hive means, don't install templates on CI/developer machine, instead create new temporary instance $"new {arguments} --debug:disable-sdk-templates --debug:custom-hive \"{CustomHivePath}\""); await proc.Exited; return(proc); }
internal async Task <ProcessResult> RunDotNetPublishAsync(IDictionary <string, string> packageOptions = null, string additionalArgs = null) { Output.WriteLine("Publishing ASP.NET Core application..."); // Avoid restoring as part of build or publish. These projects should have already restored as part of running dotnet new. Explicitly disabling restore // should avoid any global contention and we can execute a build or publish in a lock-free way var razorSDKarg = string.IsNullOrEmpty(RazorSdkDirectoryRoot) ? string.Empty : $"/p:RazorSdkDirectoryRoot={RazorSdkDirectoryRoot}"; using var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), $"publish --no-restore -c Release /bl {razorSDKarg} {additionalArgs}", packageOptions); await result.Exited; CaptureBinLogOnFailure(result); return(new ProcessResult(result)); }
public AspNetProcess( ITestOutputHelper output, string workingDirectory, string dllPath, IDictionary <string, string> environmentVariables, bool published = true, bool hasListeningUri = true, ILogger logger = null) { _output = output; _httpClient = new HttpClient(new HttpClientHandler() { AllowAutoRedirect = true, UseCookies = true, CookieContainer = new CookieContainer(), ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator, }) { Timeout = TimeSpan.FromMinutes(2) }; _certificatePath = Path.Combine(workingDirectory, $"{Guid.NewGuid()}.pfx"); EnsureDevelopmentCertificates(); output.WriteLine("Running ASP.NET application..."); var arguments = published ? $"exec {dllPath}" : "run"; logger?.LogInformation($"AspNetProcess - process: {DotNetMuxer.MuxerPathOrDefault()} arguments: {arguments}"); var finalEnvironmentVariables = new Dictionary <string, string>(environmentVariables) { ["ASPNETCORE_KESTREL__CERTIFICATES__DEFAULT__PATH"] = _certificatePath, ["ASPNETCORE_KESTREL__CERTIFICATES__DEFAULT__PASSWORD"] = _certificatePassword }; Process = ProcessEx.Run(output, workingDirectory, DotNetMuxer.MuxerPathOrDefault(), arguments, envVars: finalEnvironmentVariables); logger?.LogInformation("AspNetProcess - process started"); if (hasListeningUri) { logger?.LogInformation("AspNetProcess - Getting listening uri"); ListeningUri = GetListeningUri(output) ?? throw new InvalidOperationException("Couldn't find the listening URL."); logger?.LogInformation($"AspNetProcess - Got {ListeningUri.ToString()}"); } }
public AspNetProcess( ITestOutputHelper output, string workingDirectory, string dllPath, IDictionary <string, string> environmentVariables, bool published = true, bool hasListeningUri = true, ILogger logger = null) { _certificatePath = Path.Combine(workingDirectory, $"{Guid.NewGuid()}.pfx"); EnsureDevelopmentCertificates(); _output = output; _httpClient = new HttpClient(new HttpClientHandler() { AllowAutoRedirect = true, UseCookies = true, CookieContainer = new CookieContainer(), ServerCertificateCustomValidationCallback = (request, certificate, chain, errors) => (certificate.Subject != "CN=localhost" && errors == SslPolicyErrors.None) || certificate?.Thumbprint == _certificateThumbprint, }) { Timeout = TimeSpan.FromMinutes(2) }; output.WriteLine("Running ASP.NET application..."); var arguments = published ? $"exec {dllPath}" : "run"; logger?.LogInformation($"AspNetProcess - process: {DotNetMuxer.MuxerPathOrDefault()} arguments: {arguments}"); var finalEnvironmentVariables = new Dictionary <string, string>(environmentVariables) { ["ASPNETCORE_Kestrel__Certificates__Default__Path"] = _certificatePath, ["ASPNETCORE_Kestrel__Certificates__Default__Password"] = _certificatePassword }; Process = ProcessEx.Run(output, workingDirectory, DotNetMuxer.MuxerPathOrDefault(), arguments, envVars: finalEnvironmentVariables); logger?.LogInformation("AspNetProcess - process started"); if (hasListeningUri) { logger?.LogInformation("AspNetProcess - Getting listening uri"); ListeningUri = ResolveListeningUrl(output); logger?.LogInformation($"AspNetProcess - Got {ListeningUri}"); } }
internal async Task <ProcessEx> RunDotNetEfUpdateDatabaseAsync() { var args = $"\"{DotNetEfFullPath}\" --verbose --no-build database update"; // Only run one instance of 'dotnet new' at once, as a workaround for // https://github.com/aspnet/templating/issues/63 await DotNetNewLock.WaitAsync(); try { var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), args); await result.Exited; return(result); } finally { DotNetNewLock.Release(); } }
internal async Task <ProcessEx> RunDotNetBuildAsync(bool takeNodeLock = false) { Output.WriteLine("Building ASP.NET application..."); // This is going to trigger a build, so we need to acquire the lock like in the other cases. // We want to take the node lock as some builds run NPM as part of the build and we want to make sure // it's run without interruptions. var effectiveLock = takeNodeLock ? new OrderedLock(NodeLock, DotNetNewLock) : new OrderedLock(nodeLock: null, DotNetNewLock); await effectiveLock.WaitAsync(); try { var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), "build -c Debug"); await result.Exited; return(result); } finally { effectiveLock.Release(); } }
private static void VerifyCannotFindTemplate(ITestOutputHelper output, string templateName) { // Verify we really did remove the previous templates var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("D")); Directory.CreateDirectory(tempDir); var proc = ProcessEx.Run( output, tempDir, "dotnet", $"new \"{templateName}\""); proc.WaitForExit(assertSuccess: false); if (!proc.Error.Contains($"No templates matched the input template name: {templateName}.")) { throw new InvalidOperationException($"Failed to uninstall previous templates. The template '{templateName}' could still be found."); } Directory.Delete(tempDir); }
internal async Task <ProcessEx> RunDotNetPublishAsync(bool takeNodeLock = false, IDictionary <string, string> packageOptions = null, string additionalArgs = null) { Output.WriteLine("Publishing ASP.NET application..."); // This is going to trigger a build, so we need to acquire the lock like in the other cases. // We want to take the node lock as some builds run NPM as part of the build and we want to make sure // it's run without interruptions. var effectiveLock = takeNodeLock ? new OrderedLock(NodeLock, DotNetNewLock) : new OrderedLock(nodeLock: null, DotNetNewLock); await effectiveLock.WaitAsync(); try { var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), $"publish -c Release /bl {additionalArgs}", packageOptions); await result.Exited; CaptureBinLogOnFailure(result); return(result); } finally { effectiveLock.Release(); } }
public AspNetProcess(string workingDirectory, string projectName, string targetFrameworkOverride) { _httpClient = new HttpClient(); var buildProcess = ProcessEx.Run(workingDirectory, "dotnet", "build --no-restore -c Debug"); buildProcess.WaitForExit(assertSuccess: true); var envVars = new Dictionary <string, string> { { "ASPNETCORE_URLS", "http://127.0.0.1:0" } }; var framework = string.IsNullOrEmpty(targetFrameworkOverride) ? DefaultFramework : targetFrameworkOverride; if (framework.StartsWith("netcore")) { _process = ProcessEx.Run(workingDirectory, "dotnet", $"exec bin/Debug/{framework}/{projectName}.dll", envVars: envVars); } else { var exeFullPath = Path.Combine(workingDirectory, "bin", "Debug", framework, $"{projectName}.exe"); _process = ProcessEx.Run(workingDirectory, exeFullPath, envVars: envVars); } // Wait until the app is accepting HTTP requests var listeningMessage = _process .OutputLinesAsEnumerable .Where(line => line != null) .FirstOrDefault(line => line.StartsWith(ListeningMessagePrefix, StringComparison.Ordinal)); Assert.True(!string.IsNullOrEmpty(listeningMessage), $"ASP.NET process exited without listening for requests.\nOutput: { _process.Output }\nError: { _process.Error }"); // Verify we have a valid URL to make requests to var listeningUrlString = listeningMessage.Substring(ListeningMessagePrefix.Length); _listeningUri = new Uri(listeningUrlString, UriKind.Absolute); }
private static void ReinstallTemplatePackages(ITestOutputHelper output) { // Remove any previous or prebundled version of the template packages foreach (var packageName in _templatePackages) { var proc = ProcessEx.Run( output, AppContext.BaseDirectory, DotNetMuxer.MuxerPathOrDefault(), $"new --uninstall {packageName}"); // We don't need this command to succeed, because we'll verify next that // uninstallation had the desired effect. This command is expected to fail // in the case where the package wasn't previously installed. proc.WaitForExit(assertSuccess: false); } VerifyCannotFindTemplate(output, "ASP.NET Core Empty"); // Locate the artifacts directory containing the built template packages var solutionDir = FindAncestorDirectoryContaining("Templating.sln"); var artifactsDir = Path.Combine(solutionDir, "artifacts", "build"); var builtPackages = Directory.GetFiles(artifactsDir, "*.nupkg"); foreach (var packagePath in builtPackages) { if (_templatePackages.Any(name => Path.GetFileName(packagePath).StartsWith(name, StringComparison.OrdinalIgnoreCase))) { output.WriteLine($"Installing templates package {packagePath}..."); var proc = ProcessEx.Run( output, AppContext.BaseDirectory, DotNetMuxer.MuxerPathOrDefault(), $"new --install \"{packagePath}\""); proc.WaitForExit(assertSuccess: true); } } }
public AspNetProcess( ITestOutputHelper output, string workingDirectory, string dllPath, IDictionary <string, string> environmentVariables, bool published, bool hasListeningUri = true, bool usePublishedAppHost = false, ILogger logger = null) { _developmentCertificate = DevelopmentCertificate.Create(workingDirectory); _output = output; _httpClient = new HttpClient(new HttpClientHandler() { AllowAutoRedirect = true, UseCookies = true, CookieContainer = new CookieContainer(), ServerCertificateCustomValidationCallback = (request, certificate, chain, errors) => (certificate.Subject != "CN=localhost" && errors == SslPolicyErrors.None) || certificate?.Thumbprint == _developmentCertificate.CertificateThumbprint, }) { Timeout = TimeSpan.FromMinutes(2) }; output.WriteLine("Running ASP.NET Core application..."); string process; string arguments; if (published) { if (usePublishedAppHost) { // When publishingu used the app host to run the app. This makes it easy to consistently run for regular and single-file publish process = Path.ChangeExtension(dllPath, OperatingSystem.IsWindows() ? ".exe" : null); arguments = null; } else { process = DotNetMuxer.MuxerPathOrDefault(); arguments = $"exec {dllPath}"; } } else { process = DotNetMuxer.MuxerPathOrDefault(); arguments = "run --no-build"; } logger?.LogInformation($"AspNetProcess - process: {process} arguments: {arguments}"); var finalEnvironmentVariables = new Dictionary <string, string>(environmentVariables) { ["ASPNETCORE_Kestrel__Certificates__Default__Path"] = _developmentCertificate.CertificatePath, ["ASPNETCORE_Kestrel__Certificates__Default__Password"] = _developmentCertificate.CertificatePassword, }; Process = ProcessEx.Run(output, workingDirectory, process, arguments, envVars: finalEnvironmentVariables); logger?.LogInformation("AspNetProcess - process started"); if (hasListeningUri) { logger?.LogInformation("AspNetProcess - Getting listening uri"); ListeningUri = ResolveListeningUrl(output); logger?.LogInformation($"AspNetProcess - Got {ListeningUri}"); } }
internal async Task <ProcessResult> RunDotNetNewAsync( string templateName, string auth = null, string language = null, bool useLocalDB = false, bool noHttps = false, string[] args = null, // Used to set special options in MSBuild IDictionary <string, string> environmentVariables = null) { var hiveArg = $" --debug:disable-sdk-templates --debug:custom-hive \"{TemplatePackageInstaller.CustomHivePath}\""; var argString = $"new {templateName} {hiveArg}"; environmentVariables ??= new Dictionary <string, string>(); if (!string.IsNullOrEmpty(auth)) { argString += $" --auth {auth}"; } if (!string.IsNullOrEmpty(language)) { argString += $" -lang {language}"; } if (useLocalDB) { argString += $" --use-local-db"; } if (noHttps) { argString += $" --no-https"; } if (args != null) { foreach (var arg in args) { argString += " " + arg; } } // Save a copy of the arguments used for better diagnostic error messages later. // We omit the hive argument and the template output dir as they are not relevant and add noise. ProjectArguments = argString.Replace(hiveArg, ""); argString += $" -o {TemplateOutputDir}"; // Only run one instance of 'dotnet new' at once, as a workaround for // https://github.com/aspnet/templating/issues/63 await DotNetNewLock.WaitAsync(); try { Output.WriteLine("Acquired DotNetNewLock"); if (Directory.Exists(TemplateOutputDir)) { Output.WriteLine($"Template directory already exists, deleting contents of {TemplateOutputDir}"); Directory.Delete(TemplateOutputDir, recursive: true); } using var execution = ProcessEx.Run(Output, AppContext.BaseDirectory, DotNetMuxer.MuxerPathOrDefault(), argString, environmentVariables); await execution.Exited; return(new ProcessResult(execution)); } finally { DotNetNewLock.Release(); Output.WriteLine("Released DotNetNewLock"); } }
public AspNetProcess(ITestOutputHelper output, string workingDirectory, string projectName, string targetFrameworkOverride, bool publish) { _output = output; _httpClient = new HttpClient(); var framework = string.IsNullOrEmpty(targetFrameworkOverride) ? DefaultFramework : targetFrameworkOverride; if (publish) { output.WriteLine("Publishing ASP.NET application..."); // Workaround for issue with runtime store not yet being published // https://github.com/aspnet/Home/issues/2254#issuecomment-339709628 var extraArgs = "-p:PublishWithAspNetCoreTargetManifest=false"; ProcessEx .Run(output, workingDirectory, DotNetMuxer.MuxerPathOrDefault(), $"publish -c Release {extraArgs}") .WaitForExit(assertSuccess: true); workingDirectory = Path.Combine(workingDirectory, "bin", "Release", framework, "publish"); } else { output.WriteLine("Building ASP.NET application..."); ProcessEx .Run(output, workingDirectory, DotNetMuxer.MuxerPathOrDefault(), "build --no-restore -c Debug") .WaitForExit(assertSuccess: true); } var envVars = new Dictionary <string, string> { { "ASPNETCORE_URLS", "http://127.0.0.1:0" } }; if (!publish) { envVars["ASPNETCORE_ENVIRONMENT"] = "Development"; } output.WriteLine("Running ASP.NET application..."); if (framework.StartsWith("netcore")) { var dllPath = publish ? $"{projectName}.dll" : $"bin/Debug/{framework}/{projectName}.dll"; _process = ProcessEx.Run(output, workingDirectory, DotNetMuxer.MuxerPathOrDefault(), $"exec {dllPath}", envVars: envVars); } else { var exeFullPath = publish ? Path.Combine(workingDirectory, $"{projectName}.exe") : Path.Combine(workingDirectory, "bin", "Debug", framework, $"{projectName}.exe"); _process = ProcessEx.Run(output, workingDirectory, exeFullPath, envVars: envVars); } // Wait until the app is accepting HTTP requests output.WriteLine("Waiting until ASP.NET application is accepting connections..."); var listeningMessage = _process .OutputLinesAsEnumerable .Where(line => line != null) .FirstOrDefault(line => line.StartsWith(ListeningMessagePrefix, StringComparison.Ordinal)); Assert.True(!string.IsNullOrEmpty(listeningMessage), $"ASP.NET process exited without listening for requests.\nOutput: { _process.Output }\nError: { _process.Error }"); // Verify we have a valid URL to make requests to var listeningUrlString = listeningMessage.Substring(ListeningMessagePrefix.Length); _listeningUri = new Uri(listeningUrlString, UriKind.Absolute); output.WriteLine($"Detected that ASP.NET application is accepting connections on: {listeningUrlString}"); }