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:
parent
e4cf7a6d3e
commit
e33cb4a354
|
|
@ -3,9 +3,6 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
|
|
||||||
<!-- Temporary workaround for a VS build issue -->
|
|
||||||
<BlazorRebuildOnFileChange>false</BlazorRebuildOnFileChange>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,10 @@
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Blazor.Server;
|
using Microsoft.AspNetCore.Blazor.Server;
|
||||||
using Microsoft.AspNetCore.Blazor.Server.AutoRebuild;
|
using Microsoft.AspNetCore.Blazor.Server.AutoRebuild;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
@ -19,7 +22,48 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
private static string[] _includedSuffixes = new[] { ".cs", ".cshtml", "index.html" };
|
private static string[] _includedSuffixes = new[] { ".cs", ".cshtml", "index.html" };
|
||||||
private static string[] _excludedDirectories = new[] { "obj", "bin" };
|
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
|
// Currently this only supports VS for Windows. Later on we can add
|
||||||
// an IRebuildService implementation for VS for Mac, etc.
|
// an IRebuildService implementation for VS for Mac, etc.
|
||||||
|
|
@ -91,6 +135,12 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
fsw.IncludeSubdirectories = true;
|
fsw.IncludeSubdirectories = true;
|
||||||
fsw.EnableRaisingEvents = 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)
|
void OnEvent(object sender, FileSystemEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
if (!File.Exists(eventArgs.FullPath))
|
if (!File.Exists(eventArgs.FullPath))
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ using Microsoft.Extensions.FileProviders;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using System.Net.Mime;
|
using System.Net.Mime;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Builder
|
namespace Microsoft.AspNetCore.Builder
|
||||||
{
|
{
|
||||||
|
|
@ -16,6 +17,8 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class BlazorAppBuilderExtensions
|
public static class BlazorAppBuilderExtensions
|
||||||
{
|
{
|
||||||
|
const string DevServerApplicationName = "dotnet-blazor";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configures the middleware pipeline to work with Blazor.
|
/// Configures the middleware pipeline to work with Blazor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -54,7 +57,14 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
|
|
||||||
if (env.IsDevelopment() && config.EnableAutoRebuilding)
|
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
|
// First, match the request against files in the client app dist directory
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,6 @@
|
||||||
https://dotnet.myget.org/f/blazor-dev/api/v3/index.json;
|
https://dotnet.myget.org/f/blazor-dev/api/v3/index.json;
|
||||||
</RestoreSources>
|
</RestoreSources>
|
||||||
<LangVersion>7.3</LangVersion>
|
<LangVersion>7.3</LangVersion>
|
||||||
|
|
||||||
<!-- Temporary workaround for a VS build issue -->
|
|
||||||
<BlazorRebuildOnFileChange>false</BlazorRebuildOnFileChange>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue