Simple autorebuild mechanism for hosted apps (#787)

* Simple autorebuild mechanism for hosted apps

* CR feedback: DI changes; use Directory.EnumerateFiles

* CR feedback: Ensure FileSystemWatcher isn't GCed
This commit is contained in:
Steve Sanderson 2018-05-22 13:02:36 +01:00 committed by GitHub
parent e4cf7a6d3e
commit e33cb4a354
4 changed files with 62 additions and 8 deletions

View File

@ -3,9 +3,6 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<OutputType>Exe</OutputType>
<!-- Temporary workaround for a VS build issue -->
<BlazorRebuildOnFileChange>false</BlazorRebuildOnFileChange>
</PropertyGroup>
<ItemGroup>

View File

@ -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<object> _uncollectableWatchers = new List<object>();
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<ILoggerFactory>();
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))

View File

@ -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
/// </summary>
public static class BlazorAppBuilderExtensions
{
const string DevServerApplicationName = "dotnet-blazor";
/// <summary>
/// Configures the middleware pipeline to work with Blazor.
/// </summary>
@ -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

View File

@ -9,9 +9,6 @@
https://dotnet.myget.org/f/blazor-dev/api/v3/index.json;
</RestoreSources>
<LangVersion>7.3</LangVersion>
<!-- Temporary workaround for a VS build issue -->
<BlazorRebuildOnFileChange>false</BlazorRebuildOnFileChange>
</PropertyGroup>
<ItemGroup>