diff --git a/samples/HostedInAspNet.Client/HostedInAspNet.Client.csproj b/samples/HostedInAspNet.Client/HostedInAspNet.Client.csproj index 038ec80f9f..fbec52a713 100644 --- a/samples/HostedInAspNet.Client/HostedInAspNet.Client.csproj +++ b/samples/HostedInAspNet.Client/HostedInAspNet.Client.csproj @@ -3,9 +3,6 @@ netstandard2.0 Exe - - - false diff --git a/src/Microsoft.AspNetCore.Blazor.Server/AutoRebuild/AutoRebuildExtensions.cs b/src/Microsoft.AspNetCore.Blazor.Server/AutoRebuild/AutoRebuildExtensions.cs index a54e023966..471f6e9545 100644 --- a/src/Microsoft.AspNetCore.Blazor.Server/AutoRebuild/AutoRebuildExtensions.cs +++ b/src/Microsoft.AspNetCore.Blazor.Server/AutoRebuild/AutoRebuildExtensions.cs @@ -3,7 +3,10 @@ using Microsoft.AspNetCore.Blazor.Server; using Microsoft.AspNetCore.Blazor.Server.AutoRebuild; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -19,7 +22,48 @@ namespace Microsoft.AspNetCore.Builder private static string[] _includedSuffixes = new[] { ".cs", ".cshtml", "index.html" }; private static string[] _excludedDirectories = new[] { "obj", "bin" }; - public static void UseAutoRebuild(this IApplicationBuilder appBuilder, BlazorConfig config) + // To ensure the FileSystemWatchers aren't collected, reference them + // in this static list. They never need to be removed because there's no + // way to remove middleware once it's registered. + private static List _uncollectableWatchers = new List(); + + public static void UseHostedAutoRebuild(this IApplicationBuilder appBuilder, BlazorConfig config, string hostAppContentRootPath) + { + var isFirstFileWrite = true; + WatchFileSystem(config, () => + { + if (isFirstFileWrite) + { + try + { + // Touch any .cs file to force the host project to rebuild + // (which in turn rebuilds the client, since it's referenced) + var fileToTouch = Directory.EnumerateFiles( + hostAppContentRootPath, + "*.cs", + SearchOption.AllDirectories).FirstOrDefault(); + + if (!string.IsNullOrEmpty(fileToTouch)) + { + File.SetLastWriteTime(fileToTouch, DateTime.Now); + } + } + catch (Exception ex) + { + // If we don't have permission to write these files, autorebuild will not be enabled + var loggerFactory = appBuilder.ApplicationServices.GetRequiredService(); + var logger = loggerFactory.CreateLogger(typeof (AutoRebuildExtensions)); + logger?.LogWarning(ex, + "Cannot autorebuild because there was an error when writing to a file in '{0}'.", + hostAppContentRootPath); + } + + isFirstFileWrite = false; + } + }); + } + + public static void UseDevServerAutoRebuild(this IApplicationBuilder appBuilder, BlazorConfig config) { // Currently this only supports VS for Windows. Later on we can add // an IRebuildService implementation for VS for Mac, etc. @@ -91,6 +135,12 @@ namespace Microsoft.AspNetCore.Builder fsw.IncludeSubdirectories = true; fsw.EnableRaisingEvents = true; + // Ensure the watcher is not GCed for as long as the app lives + lock (_uncollectableWatchers) + { + _uncollectableWatchers.Add(fsw); + } + void OnEvent(object sender, FileSystemEventArgs eventArgs) { if (!File.Exists(eventArgs.FullPath)) diff --git a/src/Microsoft.AspNetCore.Blazor.Server/BlazorAppBuilderExtensions.cs b/src/Microsoft.AspNetCore.Blazor.Server/BlazorAppBuilderExtensions.cs index 9c74a6176d..4bc987345c 100644 --- a/src/Microsoft.AspNetCore.Blazor.Server/BlazorAppBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Blazor.Server/BlazorAppBuilderExtensions.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.FileProviders; using Microsoft.AspNetCore.Hosting; using Microsoft.Net.Http.Headers; using System.Net.Mime; +using System; namespace Microsoft.AspNetCore.Builder { @@ -16,6 +17,8 @@ namespace Microsoft.AspNetCore.Builder /// public static class BlazorAppBuilderExtensions { + const string DevServerApplicationName = "dotnet-blazor"; + /// /// Configures the middleware pipeline to work with Blazor. /// @@ -54,7 +57,14 @@ namespace Microsoft.AspNetCore.Builder if (env.IsDevelopment() && config.EnableAutoRebuilding) { - applicationBuilder.UseAutoRebuild(config); + if (env.ApplicationName.Equals(DevServerApplicationName, StringComparison.OrdinalIgnoreCase)) + { + applicationBuilder.UseDevServerAutoRebuild(config); + } + else + { + applicationBuilder.UseHostedAutoRebuild(config, env.ContentRootPath); + } } // First, match the request against files in the client app dist directory diff --git a/src/Microsoft.AspNetCore.Blazor.Templates/content/BlazorHosted-CSharp/BlazorHosted-CSharp.Client/BlazorHosted-CSharp.Client.csproj b/src/Microsoft.AspNetCore.Blazor.Templates/content/BlazorHosted-CSharp/BlazorHosted-CSharp.Client/BlazorHosted-CSharp.Client.csproj index 02613021e2..ff0f4e61aa 100644 --- a/src/Microsoft.AspNetCore.Blazor.Templates/content/BlazorHosted-CSharp/BlazorHosted-CSharp.Client/BlazorHosted-CSharp.Client.csproj +++ b/src/Microsoft.AspNetCore.Blazor.Templates/content/BlazorHosted-CSharp/BlazorHosted-CSharp.Client/BlazorHosted-CSharp.Client.csproj @@ -9,9 +9,6 @@ https://dotnet.myget.org/f/blazor-dev/api/v3/index.json; 7.3 - - - false