public async Task ProcessAsync_AddsNoRestoreSwitch() { // Arrange var filter = new NoRestoreFilter(); var context = new DotNetWatchContext { Iteration = 0, ProcessSpec = new ProcessSpec { Arguments = _arguments, } }; await filter.ProcessAsync(context, default); context.ChangedFile = new FileItem { FilePath = "Program.cs" }; context.Iteration++; // Act await filter.ProcessAsync(context, default); // Assert Assert.Equal(new[] { "run", "--no-restore" }, context.ProcessSpec.Arguments); }
public async ValueTask ProcessAsync(DotNetWatchContext context, CancellationToken cancellationToken) { using var fileSetWatcher = new FileSetWatcher(context.FileSet, _reporter); while (!cancellationToken.IsCancellationRequested) { var arguments = context.RequiresMSBuildRevaluation ? new[] { "msbuild", "/t:Build", "/restore", "/nologo" } : new[] { "msbuild", "/t:Build", "/nologo" }; var processSpec = new ProcessSpec { Executable = _muxer, Arguments = arguments, WorkingDirectory = context.ProcessSpec.WorkingDirectory, }; _reporter.Output("Building..."); var exitCode = await _processRunner.RunAsync(processSpec, cancellationToken); if (exitCode == 0) { return; } // If the build fails, we'll retry until we have a successful build. context.ChangedFile = await fileSetWatcher.GetChangedFileAsync(cancellationToken, () => _reporter.Warn("Waiting for a file to change before restarting dotnet...")); } }
public async ValueTask TryHandleFileAction_CausesBrowserRefreshForNonCssFile() { // Arrange var server = new Mock <BrowserRefreshServer>(NullReporter.Singleton); byte[] writtenBytes = null; server.Setup(s => s.SendMessage(It.IsAny <byte[]>(), It.IsAny <CancellationToken>())) .Callback((byte[] bytes, CancellationToken cts) => { writtenBytes = bytes; }); var fileContentHandler = new FileChangeHandler(NullReporter.Singleton); var context = new DotNetWatchContext { BrowserRefreshServer = server.Object, }; var file = new FileItem { FilePath = "Test.js", IsStaticFile = true, StaticWebAssetPath = "Test.js" }; // Act var result = await fileContentHandler.TryHandleFileAction(context, file, default); // Assert Assert.True(result); Assert.NotNull(writtenBytes); var deserialized = JsonSerializer.Deserialize <UpdateStaticFileMessage>(writtenBytes, new JsonSerializerOptions(JsonSerializerDefaults.Web)); Assert.Equal("UpdateStaticFile", deserialized.Type); Assert.Equal("content/Test.js", deserialized.Path); }
public async ValueTask ProcessAsync(DotNetWatchContext context, CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) { var arguments = context.Iteration == 0 || (context.ChangedFile?.FilePath is string changedFile && changedFile.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase)) ? new[] { "msbuild", "/t:Build", "/restore", "/nologo" } : new[] { "msbuild", "/t:Build", "/nologo" }; var processSpec = new ProcessSpec { Executable = _muxer, Arguments = arguments, WorkingDirectory = context.ProcessSpec.WorkingDirectory, }; _reporter.Output("Building..."); var exitCode = await _processRunner.RunAsync(processSpec, cancellationToken); context.FileSet = await _fileSetFactory.CreateAsync(cancellationToken); if (exitCode == 0) { return; } // If the build fails, we'll retry until we have a successful build. using var fileSetWatcher = new FileSetWatcher(context.FileSet, _reporter); await fileSetWatcher.GetChangedFileAsync(cancellationToken, () => _reporter.Warn("Waiting for a file to change before restarting dotnet...")); } }
public async Task ProcessAsync_AddsNoRestoreSwitch_WithAdditionalArguments() { // Arrange var filter = new NoRestoreFilter(); var context = new DotNetWatchContext { Iteration = 0, ProcessSpec = new ProcessSpec { Arguments = new[] { "run", "-f", ToolsetInfo.CurrentTargetFramework, "--", "foo=bar" }, } }; await filter.ProcessAsync(context, default); context.ChangedFile = new FileItem { FilePath = "Program.cs" }; context.Iteration++; // Act await filter.ProcessAsync(context, default); // Assert Assert.Equal(new[] { "run", "--no-restore", "-f", ToolsetInfo.CurrentTargetFramework, "--", "foo=bar" }, context.ProcessSpec.Arguments); }
public async ValueTask <bool> TryHandleFileChange(DotNetWatchContext context, FileItem file, CancellationToken cancellationToken) { return (await _staticFileHandler.TryHandleFileChange(context, file, cancellationToken) || await _scopedCssFileHandler.TryHandleFileChange(context, file, cancellationToken) || await _compilationHandler.TryHandleFileChange(context, file, cancellationToken)); }
private static bool CanLaunchBrowser(DotNetWatchContext context, out string launchUrl) { launchUrl = null; var reporter = context.Reporter; if (!context.FileSet.IsNetCoreApp31OrNewer) { // Browser refresh middleware supports 3.1 or newer reporter.Verbose("Browser refresh is only supported in .NET Core 3.1 or newer projects."); return(false); } var dotnetCommand = context.ProcessSpec.Arguments.FirstOrDefault(); if (!string.Equals(dotnetCommand, "run", StringComparison.Ordinal)) { reporter.Verbose("Browser refresh is only supported for run commands."); return(false); } // We're executing the run-command. Determine if the launchSettings allows it var launchSettingsPath = Path.Combine(context.ProcessSpec.WorkingDirectory, "Properties", "launchSettings.json"); if (!File.Exists(launchSettingsPath)) { reporter.Verbose($"No launchSettings.json file found at {launchSettingsPath}. Unable to determine if browser refresh is allowed."); return(false); } LaunchSettingsJson launchSettings; try { launchSettings = JsonSerializer.Deserialize <LaunchSettingsJson>( File.ReadAllText(launchSettingsPath), new JsonSerializerOptions(JsonSerializerDefaults.Web)); } catch (Exception ex) { reporter.Verbose($"Error reading launchSettings.json: {ex}."); return(false); } var defaultProfile = launchSettings.Profiles.FirstOrDefault(f => f.Value.CommandName == "Project").Value; if (defaultProfile is null) { reporter.Verbose("Unable to find default launchSettings profile."); return(false); } if (!defaultProfile.LaunchBrowser) { reporter.Verbose("launchSettings does not allow launching browsers."); return(false); } launchUrl = defaultProfile.LaunchUrl; return(true); }
public async Task ProcessAsync_DoesNotModifyArgumentsForUnknownCommands() { // Arrange var filter = new NoRestoreFilter(); var arguments = new[] { "ef", "database", "update" }; var context = new DotNetWatchContext { Iteration = 0, ProcessSpec = new ProcessSpec { Arguments = arguments, } }; await filter.ProcessAsync(context, default); context.ChangedFile = new FileItem { FilePath = "Program.cs" }; context.Iteration++; // Act await filter.ProcessAsync(context, default); // Assert Assert.Same(arguments, context.ProcessSpec.Arguments); }
public async Task InitializeAsync_ConfiguresEnvironmentVariables() { // Arrange var applier = new DefaultDeltaApplier(Mock.Of <IReporter>()) { SuppressNamedPipeForTests = true }; var process = new ProcessSpec(); var fileSet = new FileSet(null, new[] { new FileItem { FilePath = "Test.cs" }, }); var context = new DotNetWatchContext { ProcessSpec = process, FileSet = fileSet, Iteration = 0 }; // Act await applier.InitializeAsync(context, default); // Assert Assert.Equal("debug", process.EnvironmentVariables["DOTNET_MODIFIABLE_ASSEMBLIES"]); Assert.NotEmpty(process.EnvironmentVariables["DOTNET_HOTRELOAD_NAMEDPIPE_NAME"]); Assert.NotEmpty(process.EnvironmentVariables.DotNetStartupHooks); }
public async Task ProcessAsync_LeavesArgumentsUnchangedIfMsBuildRevaluationIsRequired() { // Arrange var filter = new NoRestoreFilter(); var context = new DotNetWatchContext { Iteration = 0, ProcessSpec = new ProcessSpec { Arguments = _arguments, } }; await filter.ProcessAsync(context, default); context.ChangedFile = new FileItem { FilePath = "Test.proj" }; context.RequiresMSBuildRevaluation = true; context.Iteration++; // Act await filter.ProcessAsync(context, default); // Assert Assert.Same(_arguments, context.ProcessSpec.Arguments); }
public async Task ProcessAsync_LeavesArgumentsUnchangedIfOptimizationIsSuppressed() { // Arrange var filter = new NoRestoreFilter(); var context = new DotNetWatchContext { Iteration = 0, ProcessSpec = new ProcessSpec { Arguments = _arguments, }, SuppressMSBuildIncrementalism = true, }; await filter.ProcessAsync(context, default); context.ChangedFile = new FileItem { FilePath = "Program.cs" }; context.Iteration++; // Act await filter.ProcessAsync(context, default); // Assert Assert.Same(_arguments, context.ProcessSpec.Arguments); }
public async Task ProcessAsync_SetsEvaluationRequired_IfMSBuildFileChanges_ButIsNotChangedFile() { // There's a chance that the watcher does not correctly report edits to msbuild files on // concurrent edits. MSBuildEvaluationFilter uses timestamps to additionally track changes to these files. // Arrange var fileSet = new FileSet(new[] { "Controlller.cs", "Proj.csproj" }); var fileSetFactory = Mock.Of <IFileSetFactory>(f => f.CreateAsync(It.IsAny <CancellationToken>()) == Task.FromResult <IFileSet>(fileSet)); var filter = new TestableMSBuildEvaluationFilter(fileSetFactory) { Timestamps = { ["Controller.cs"] = new DateTime(1000), ["Proj.csproj"] = new DateTime(1000), } }; var context = new DotNetWatchContext { Iteration = 0, }; await filter.ProcessAsync(context, default); context.RequiresMSBuildRevaluation = false; context.ChangedFile = "Controller.cs"; context.Iteration++; filter.Timestamps["Proj.csproj"] = new DateTime(1007); // Act await filter.ProcessAsync(context, default); // Assert Assert.True(context.RequiresMSBuildRevaluation); }
public async Task ProcessAsync_EvaluateFileSetOnEveryChangeIfOptimizationIsSuppressed() { // Arrange var filter = new MSBuildEvaluationFilter(_fileSetFactory); var context = new DotNetWatchContext { Iteration = 0, SuppressMSBuildIncrementalism = true, }; await filter.ProcessAsync(context, default); context.Iteration++; context.ChangedFile = new FileItem { FilePath = "Controller.cs" }; context.RequiresMSBuildRevaluation = false; // Act await filter.ProcessAsync(context, default); // Assert Assert.True(context.RequiresMSBuildRevaluation); Mock.Get(_fileSetFactory).Verify(v => v.CreateAsync(It.IsAny <CancellationToken>()), Times.Exactly(2)); }
public async ValueTask <bool> TryHandleFileChange(DotNetWatchContext context, FileItem file, CancellationToken cancellationToken) { HotReloadEventSource.Log.HotReloadStart(HotReloadEventSource.StartType.ScopedCssHandler); if (!file.FilePath.EndsWith(".razor.css", StringComparison.Ordinal) && !file.FilePath.EndsWith(".cshtml.css", StringComparison.Ordinal)) { HotReloadEventSource.Log.HotReloadEnd(HotReloadEventSource.StartType.ScopedCssHandler); return(default);
public async Task <ImmutableArray <string> > GetApplyUpdateCapabilitiesAsync(DotNetWatchContext context, CancellationToken cancellationToken) { var result = await Task.WhenAll( _wasmApplier.GetApplyUpdateCapabilitiesAsync(context, cancellationToken), _hostApplier.GetApplyUpdateCapabilitiesAsync(context, cancellationToken)); return(result[0].Intersect(result[1], StringComparer.OrdinalIgnoreCase).ToImmutableArray()); }
public async ValueTask <bool> TryHandleFileChange(DotNetWatchContext context, FileItem file, CancellationToken cancellationToken) { HotReloadEventSource.Log.HotReloadStart(HotReloadEventSource.StartType.Main); var fileHandlerResult = await _staticFileHandler.TryHandleFileChange(context, file, cancellationToken) || await _scopedCssFileHandler.TryHandleFileChange(context, file, cancellationToken) || await _compilationHandler.TryHandleFileChange(context, file, cancellationToken); HotReloadEventSource.Log.HotReloadEnd(HotReloadEventSource.StartType.Main); return(fileHandlerResult); }
public async ValueTask ReportDiagnosticsAsync(DotNetWatchContext context, IEnumerable <string> diagnostics, CancellationToken cancellationToken) { if (context.BrowserRefreshServer != null) { var message = new HotReloadDiagnostics { Diagnostics = diagnostics }; await context.BrowserRefreshServer.SendJsonSerlialized(message, cancellationToken); } }
public async ValueTask <bool> TryHandleFileChange(DotNetWatchContext context, FileItem file, CancellationToken cancellationToken) { if (await _staticFileHandler.TryHandleFileChange(context, file, cancellationToken)) { return(true); } if (await _compilationHandler.TryHandleFileChange(context, file, cancellationToken)) // This needs to be 6.0 { return(true); } return(false); }
public async ValueTask ProcessAsync(DotNetWatchContext context, CancellationToken cancellationToken) { tempContext = context; if (_suppressLaunchBrowser) { return; } if (context.Iteration == 0) { _reporter = context.Reporter; if (CanLaunchBrowser(context, out var launchPath)) { context.Reporter.Verbose("dotnet-watch is configured to launch a browser on ASP.NET Core application startup."); _canLaunchBrowser = true; _launchPath = launchPath; _cancellationToken = cancellationToken; // We've redirected the output, but want to ensure that it continues to appear in the user's console. context.ProcessSpec.OnOutput += (_, eventArgs) => Console.WriteLine(eventArgs.Data); context.ProcessSpec.OnOutput += OnOutput; if (!_suppressBrowserRefresh) { _refreshServer = new BrowserRefreshServer(context.Reporter); var serverUrl = await _refreshServer.StartAsync(cancellationToken); context.Reporter.Verbose($"Refresh server running at {serverUrl}."); context.ProcessSpec.EnvironmentVariables["ASPNETCORE_AUTO_RELOAD_WS_ENDPOINT"] = serverUrl; var pathToMiddleware = Path.Combine(AppContext.BaseDirectory, "middleware", "Microsoft.AspNetCore.Watch.BrowserRefresh.dll"); context.ProcessSpec.EnvironmentVariables["DOTNET_STARTUP_HOOKS"] = pathToMiddleware; context.ProcessSpec.EnvironmentVariables["ASPNETCORE_HOSTINGSTARTUPASSEMBLIES"] = "Microsoft.AspNetCore.Watch.BrowserRefresh"; } } } if (_canLaunchBrowser) { if (context.Iteration > 0) { // We've detected a change. Notify the browser. await SendMessage(WaitMessage, cancellationToken); } } }
public async Task ProcessAsync_LeavesArgumentsUnchangedOnFirstRun() { // Arrange var filter = new NoRestoreFilter(); var context = new DotNetWatchContext { ProcessSpec = new ProcessSpec { Arguments = _arguments, } }; // Act await filter.ProcessAsync(context, default); // Assert Assert.Same(_arguments, context.ProcessSpec.Arguments); }
public async ValueTask InitializeAsync(DotNetWatchContext context, CancellationToken cancellationToken) { if (_pipe is not null) { _pipe.Close(); await _pipe.DisposeAsync(); } _pipe = new NamedPipeServerStream("netcore-hot-reload", PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.CurrentUserOnly); _task = _pipe.WaitForConnectionAsync(cancellationToken); if (context.Iteration == 0) { var deltaApplier = Path.Combine(AppContext.BaseDirectory, "hotreload", "Microsoft.Extensions.AspNetCoreDeltaApplier.dll"); context.ProcessSpec.EnvironmentVariables.DotNetStartupHooks.Add(deltaApplier); // Configure the app for EnC context.ProcessSpec.EnvironmentVariables["DOTNET_MODIFIABLE_ASSEMBLIES"] = "debug"; } }
public async ValueTask ProcessAsync(DotNetWatchContext context, CancellationToken cancellationToken) { if (_suppressLaunchBrowser) { return; } if (context.Iteration == 0) { _reporter = context.Reporter; if (CanLaunchBrowser(context, out var launchPath)) { context.Reporter.Verbose("dotnet-watch is configured to launch a browser on ASP.NET Core application startup."); _launchPath = launchPath; _cancellationToken = cancellationToken; // We've redirected the output, but want to ensure that it continues to appear in the user's console. context.ProcessSpec.OnOutput += (_, eventArgs) => Console.WriteLine(eventArgs.Data); context.ProcessSpec.OnOutput += OnOutput; if (!_suppressBrowserRefresh) { _refreshServer = new BrowserRefreshServer(context.Reporter); context.BrowserRefreshServer = _refreshServer; var serverUrls = string.Join(',', await _refreshServer.StartAsync(cancellationToken)); context.Reporter.Verbose($"Refresh server running at {serverUrls}."); context.ProcessSpec.EnvironmentVariables["ASPNETCORE_AUTO_RELOAD_WS_ENDPOINT"] = serverUrls; var pathToMiddleware = Path.Combine(AppContext.BaseDirectory, "middleware", "Microsoft.AspNetCore.Watch.BrowserRefresh.dll"); context.ProcessSpec.EnvironmentVariables.DotNetStartupHooks.Add(pathToMiddleware); context.ProcessSpec.EnvironmentVariables.AspNetCoreHostingStartupAssemblies.Add("Microsoft.AspNetCore.Watch.BrowserRefresh"); } } } else if (!_suppressBrowserRefresh) { // We've detected a change. Notify the browser. await(_refreshServer?.SendWaitMessageAsync(cancellationToken) ?? default); } }
public async ValueTask ProcessAsync(DotNetWatchContext context, CancellationToken cancellationToken) { if (_suppressBrowserRefresh) { return; } if (context.Iteration == 0) { if (context.ProjectGraph is null) { _reporter.Verbose("Unable to determine if this project is a webapp."); return; } else if (IsWebApp(context.ProjectGraph)) { _reporter.Verbose("Configuring the app to use browser-refresh middleware."); } else { _reporter.Verbose("Skipping configuring browser-refresh middleware since this is not a webapp."); return; } _refreshServer = new BrowserRefreshServer(context.Reporter); context.BrowserRefreshServer = _refreshServer; var serverUrls = string.Join(',', await _refreshServer.StartAsync(cancellationToken)); context.Reporter.Verbose($"Refresh server running at {serverUrls}."); context.ProcessSpec.EnvironmentVariables["ASPNETCORE_AUTO_RELOAD_WS_ENDPOINT"] = serverUrls; context.ProcessSpec.EnvironmentVariables["ASPNETCORE_AUTO_RELOAD_WS_KEY"] = _refreshServer.ServerKey; var pathToMiddleware = Path.Combine(AppContext.BaseDirectory, "middleware", "Microsoft.AspNetCore.Watch.BrowserRefresh.dll"); context.ProcessSpec.EnvironmentVariables.DotNetStartupHooks.Add(pathToMiddleware); context.ProcessSpec.EnvironmentVariables.AspNetCoreHostingStartupAssemblies.Add("Microsoft.AspNetCore.Watch.BrowserRefresh"); } else if (!_suppressBrowserRefresh) { // We've detected a change. Notify the browser. await(_refreshServer?.SendWaitMessageAsync(cancellationToken) ?? default); } }
public async Task ProcessAsync_EvaluatesFileSetIfProjFileChanges() { // Arrange var filter = new MSBuildEvaluationFilter(_fileSetFactory); var context = new DotNetWatchContext { Iteration = 0, }; await filter.ProcessAsync(context, default); context.Iteration++; context.ChangedFile = "Test.csproj"; context.RequiresMSBuildRevaluation = false; // Act await filter.ProcessAsync(context, default); // Assert Assert.True(context.RequiresMSBuildRevaluation); }
public async ValueTask <bool> TryHandleFileChange(DotNetWatchContext context, FileItem[] files, CancellationToken cancellationToken) { HotReloadEventSource.Log.HotReloadStart(HotReloadEventSource.StartType.Main); var fileHandlerResult = false; for (var i = files.Length - 1; i >= 0; i--) { var file = files[i]; if (await _staticFileHandler.TryHandleFileChange(context, file, cancellationToken) || await _scopedCssFileHandler.TryHandleFileChange(context, file, cancellationToken)) { fileHandlerResult = true; } } fileHandlerResult |= await _compilationHandler.TryHandleFileChange(context, files, cancellationToken); HotReloadEventSource.Log.HotReloadEnd(HotReloadEventSource.StartType.Main); return(fileHandlerResult); }
public async Task ProcessAsync_DoesNotEvaluateFileSetIfNonProjFileChanges() { // Arrange var filter = new MSBuildEvaluationFilter(_fileSetFactory); var context = new DotNetWatchContext { Iteration = 0, }; await filter.ProcessAsync(context, default); context.Iteration++; context.ChangedFile = "Controller.cs"; context.RequiresMSBuildRevaluation = false; // Act await filter.ProcessAsync(context, default); // Assert Assert.False(context.RequiresMSBuildRevaluation); Mock.Get(_fileSetFactory).Verify(v => v.CreateAsync(It.IsAny <CancellationToken>()), Times.Once()); }
private static bool CanLaunchBrowser(DotNetWatchContext context, out string launchUrl) { launchUrl = null; var reporter = context.Reporter; if (!context.FileSet.Project.IsNetCoreApp31OrNewer()) { // Browser refresh middleware supports 3.1 or newer reporter.Verbose("Browser refresh is only supported in .NET Core 3.1 or newer projects."); return(false); } var dotnetCommand = context.ProcessSpec.Arguments.FirstOrDefault(); if (!string.Equals(dotnetCommand, "run", StringComparison.Ordinal)) { reporter.Verbose("Browser refresh is only supported for run commands."); return(false); } if (context.DefaultLaunchSettingsProfile is not { LaunchBrowser : true })
public async ValueTask ProcessAsync(DotNetWatchContext context, CancellationToken cancellationToken) { if (_suppressLaunchBrowser) { return; } if (context.Iteration == 0) { _reporter = context.Reporter; if (CanLaunchBrowser(context, out var launchPath)) { context.Reporter.Verbose("dotnet-watch is configured to launch a browser on ASP.NET Core application startup."); _canLaunchBrowser = true; _launchPath = launchPath; _cancellationToken = cancellationToken; _refreshServer = new BrowserRefreshServer(context.Reporter); var serverUrl = await _refreshServer.StartAsync(cancellationToken); context.Reporter.Verbose($"Refresh server running at {serverUrl}."); context.ProcessSpec.EnvironmentVariables["DOTNET_WATCH_REFRESH_URL"] = serverUrl; context.ProcessSpec.OnOutput += OnOutput; } } if (_canLaunchBrowser) { if (context.Iteration > 0) { // We've detected a change. Notify the browser. await _refreshServer.SendMessage(WaitMessage, cancellationToken); } } }
public async Task ProcessAsync_AddsNoRestoreSwitch_ForTestCommand() { // Arrange var filter = new NoRestoreFilter(); var context = new DotNetWatchContext { Iteration = 0, ProcessSpec = new ProcessSpec { Arguments = new[] { "test", "--filter SomeFilter" }, } }; await filter.ProcessAsync(context, default); context.ChangedFile = "Program.cs"; context.Iteration++; // Act await filter.ProcessAsync(context, default); // Assert Assert.Equal(new[] { "test", "--no-restore", "--filter SomeFilter" }, context.ProcessSpec.Arguments); }
public ValueTask InitializeAsync(DotNetWatchContext context, CancellationToken cancellationToken) { if (!SuppressNamedPipeForTests) { _pipe = new NamedPipeServerStream(_namedPipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.CurrentUserOnly); _connectionTask = _pipe.WaitForConnectionAsync(cancellationToken); _capabilities = Task.Run(async() => { try { await _connectionTask; // When the client connects, the first payload it sends is the initialization payload which includes the apply capabilities. var capabiltiies = ClientInitializationPayload.Read(_pipe).Capabilities; _reporter.Verbose($"Application supports the following capabilities {capabiltiies}."); return(capabiltiies.Split(' ').ToImmutableArray()); } catch { // Do nothing. This is awaited by Apply which will surface the error. } return(ImmutableArray <string> .Empty); }); } if (context.Iteration == 0) { var deltaApplier = Path.Combine(AppContext.BaseDirectory, "hotreload", "Microsoft.Extensions.DotNetDeltaApplier.dll"); context.ProcessSpec.EnvironmentVariables.DotNetStartupHooks.Add(deltaApplier); // Configure the app for EnC context.ProcessSpec.EnvironmentVariables["DOTNET_MODIFIABLE_ASSEMBLIES"] = "debug"; context.ProcessSpec.EnvironmentVariables["DOTNET_HOTRELOAD_NAMEDPIPE_NAME"] = _namedPipeName; } return(default);