diff --git a/src/Components/Blazor/Build/src/ReferenceFromSource.props b/src/Components/Blazor/Build/src/ReferenceFromSource.props index ca6ee1eb5429..4fef2ec2ceff 100644 --- a/src/Components/Blazor/Build/src/ReferenceFromSource.props +++ b/src/Components/Blazor/Build/src/ReferenceFromSource.props @@ -28,7 +28,7 @@ dotnet <_BlazorCliLocation>$(MSBuildThisFileDirectory)../../DevServer/src/bin/$(Configuration)/netcoreapp3.0/blazor-devserver.dll - exec "$(_BlazorCliLocation)" serve "$(MSBuildProjectDirectory)/$(OutputPath)$(TargetFileName)" $(AdditionalRunArguments) + exec "$(_BlazorCliLocation)" serve --applicationpath "$(MSBuildProjectDirectory)/$(OutputPath)$(TargetFileName)" $(AdditionalRunArguments) diff --git a/src/Components/Blazor/DevServer/src/Commands/ServeCommand.cs b/src/Components/Blazor/DevServer/src/Commands/ServeCommand.cs index b30c00d1bd2a..eb7a347051be 100644 --- a/src/Components/Blazor/DevServer/src/Commands/ServeCommand.cs +++ b/src/Components/Blazor/DevServer/src/Commands/ServeCommand.cs @@ -1,11 +1,9 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; -using System.IO; -using System.Runtime.Versioning; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.CommandLineUtils; +using Microsoft.Extensions.Hosting; namespace Microsoft.AspNetCore.Blazor.DevServer.Commands { @@ -23,28 +21,11 @@ public ServeCommand(CommandLineApplication parent) HelpOption("-?|-h|--help"); - ApplicationPath = new CommandArgument() - { - Description = "Path to the client application dll", - MultipleValues = false, - Name = "", - ShowInHelpText = true - }; - Arguments.Add(ApplicationPath); - OnExecute(Execute); } - public CommandArgument ApplicationPath { get; private set; } - private int Execute() { - if (string.IsNullOrWhiteSpace(ApplicationPath.Value)) - { - throw new InvalidOperationException($"Invalid value for parameter '{nameof(ApplicationPath)}'. Value supplied: '{ApplicationPath.Value}'"); - } - - Server.Startup.ApplicationAssembly = ApplicationPath.Value; Server.Program.BuildWebHost(RemainingArguments.ToArray()).Run(); return 0; } diff --git a/src/Components/Blazor/DevServer/src/Microsoft.AspNetCore.Blazor.DevServer.csproj b/src/Components/Blazor/DevServer/src/Microsoft.AspNetCore.Blazor.DevServer.csproj index ebdf87801f1b..b12f55ef829e 100644 --- a/src/Components/Blazor/DevServer/src/Microsoft.AspNetCore.Blazor.DevServer.csproj +++ b/src/Components/Blazor/DevServer/src/Microsoft.AspNetCore.Blazor.DevServer.csproj @@ -19,6 +19,7 @@ + diff --git a/src/Components/Blazor/DevServer/src/Server/Program.cs b/src/Components/Blazor/DevServer/src/Server/Program.cs index 55876f5959e3..38f3b0d00526 100644 --- a/src/Components/Blazor/DevServer/src/Server/Program.cs +++ b/src/Components/Blazor/DevServer/src/Server/Program.cs @@ -1,8 +1,15 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Threading; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; namespace Microsoft.AspNetCore.Blazor.DevServer.Server { @@ -18,12 +25,24 @@ public class Program /// /// Intended for framework test use only. /// - public static IWebHost BuildWebHost(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseConfiguration(new ConfigurationBuilder() - .AddCommandLine(args) - .Build()) - .UseStartup() - .Build(); + public static IHost BuildWebHost(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureHostConfiguration(cb => { + var applicationPath = args.SkipWhile(a => a != "--applicationpath").Skip(1).FirstOrDefault(); + var name = Path.ChangeExtension(applicationPath,".StaticWebAssets.xml"); + + if (name != null) + { + cb.AddInMemoryCollection(new Dictionary + { + [WebHostDefaults.StaticWebAssetsKey] = name + }); + } + }) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStaticWebAssets(); + webBuilder.UseStartup(); + }).Build(); } } diff --git a/src/Components/Blazor/DevServer/src/Server/Startup.cs b/src/Components/Blazor/DevServer/src/Server/Startup.cs index cb0301aef6b5..95f15ff3e54d 100644 --- a/src/Components/Blazor/DevServer/src/Server/Startup.cs +++ b/src/Components/Blazor/DevServer/src/Server/Startup.cs @@ -17,7 +17,12 @@ namespace Microsoft.AspNetCore.Blazor.DevServer.Server { internal class Startup { - public static string ApplicationAssembly { get; set; } + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { @@ -35,7 +40,7 @@ public void ConfigureServices(IServiceCollection services) public void Configure(IApplicationBuilder app, IWebHostEnvironment environment, IConfiguration configuration) { - var applicationAssemblyFullPath = ResolveApplicationAssemblyFullPath(environment); + var applicationAssemblyFullPath = ResolveApplicationAssemblyFullPath(); app.UseDeveloperExceptionPage(); app.UseResponseCompression(); @@ -54,15 +59,22 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment environment, }); } - private static string ResolveApplicationAssemblyFullPath(IWebHostEnvironment environment) + private string ResolveApplicationAssemblyFullPath() { - var applicationAssemblyFullPath = Path.Combine(environment.ContentRootPath, ApplicationAssembly); - if (!File.Exists(applicationAssemblyFullPath)) + const string applicationPathKey = "applicationpath"; + var configuredApplicationPath = Configuration.GetValue(applicationPathKey); + if (string.IsNullOrEmpty(configuredApplicationPath)) + { + throw new InvalidOperationException($"No value was supplied for the required option '{applicationPathKey}'."); + } + + var resolvedApplicationPath = Path.GetFullPath(configuredApplicationPath); + if (!File.Exists(resolvedApplicationPath)) { - throw new InvalidOperationException($"Application assembly not found at {applicationAssemblyFullPath}."); + throw new InvalidOperationException($"Application assembly not found at {resolvedApplicationPath}."); } - return applicationAssemblyFullPath; + return resolvedApplicationPath; } private static void EnableConfiguredPathbase(IApplicationBuilder app, IConfiguration configuration) diff --git a/src/Components/Blazor/DevServer/src/build/Microsoft.AspNetCore.Blazor.DevServer.targets b/src/Components/Blazor/DevServer/src/build/Microsoft.AspNetCore.Blazor.DevServer.targets index b39cb3949e09..2db2b153fbf1 100644 --- a/src/Components/Blazor/DevServer/src/build/Microsoft.AspNetCore.Blazor.DevServer.targets +++ b/src/Components/Blazor/DevServer/src/build/Microsoft.AspNetCore.Blazor.DevServer.targets @@ -2,6 +2,6 @@ <_BlazorDevServerDll>$(MSBuildThisFileDirectory)../tools/blazor-devserver.dll dotnet - "$(_BlazorDevServerDll)" serve "$(MSBuildProjectDirectory)/$(OutputPath)$(TargetFileName)" + "$(_BlazorDevServerDll)" serve --applicationpath "$(MSBuildProjectDirectory)/$(OutputPath)$(TargetFileName)" diff --git a/src/Components/build.cmd b/src/Components/build.cmd index 2406296662e9..35fb6cc3a3be 100644 --- a/src/Components/build.cmd +++ b/src/Components/build.cmd @@ -1,3 +1,3 @@ @ECHO OFF SET RepoRoot=%~dp0..\.. -%RepoRoot%\build.cmd -projects %~dp0**\*.*proj %* +%RepoRoot%\build.cmd -projects %~dp0**\*.*proj "/p:EnforceE2ETestPrerequisites=true" %* diff --git a/src/Components/build.sh b/src/Components/build.sh index 7046bb98a0fc..fa8fecd0e01f 100755 --- a/src/Components/build.sh +++ b/src/Components/build.sh @@ -4,4 +4,4 @@ set -euo pipefail DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" repo_root="$DIR/../.." -"$repo_root/build.sh" --projects "$DIR/**/*.*proj" "$@" +"$repo_root/build.sh" --projects "$DIR/**/*.*proj" "/p:EnforceE2ETestPrerequisites=true" "$@" diff --git a/src/Components/test/E2ETest/Infrastructure/ServerFixtures/DevHostServerFixture.cs b/src/Components/test/E2ETest/Infrastructure/ServerFixtures/DevHostServerFixture.cs index 0526e940aeee..897be5dd5d33 100644 --- a/src/Components/test/E2ETest/Infrastructure/ServerFixtures/DevHostServerFixture.cs +++ b/src/Components/test/E2ETest/Infrastructure/ServerFixtures/DevHostServerFixture.cs @@ -2,7 +2,13 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.Hosting; +using System; using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; using DevHostServerProgram = Microsoft.AspNetCore.Blazor.DevServer.Server.Program; namespace Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures @@ -22,7 +28,8 @@ protected override IWebHost CreateWebHost() { "--urls", "http://127.0.0.1:0", "--contentroot", ContentRoot, - "--pathbase", PathBase + "--pathbase", PathBase, + "--applicationpath", typeof(TProgram).Assembly.Location, }; if (!string.IsNullOrEmpty(Environment)) @@ -31,7 +38,29 @@ protected override IWebHost CreateWebHost() args.Add(Environment); } - return DevHostServerProgram.BuildWebHost(args.ToArray()); + return new FakeWebHost(DevHostServerProgram.BuildWebHost(args.ToArray())); + } + + private class FakeWebHost : IWebHost + { + private readonly IHost _realHost; + + public FakeWebHost(IHost realHost) + { + _realHost = realHost; + } + + public IFeatureCollection ServerFeatures => ((IServer)_realHost.Services.GetService(typeof(IServer))).Features; + + public IServiceProvider Services => _realHost.Services; + + public void Dispose() => _realHost.Dispose(); + + public void Start() => _realHost.Start(); + + public Task StartAsync(CancellationToken cancellationToken = default) => _realHost.StartAsync(); + + public Task StopAsync(CancellationToken cancellationToken = default) => _realHost.StopAsync(); } } } diff --git a/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj b/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj index 477e5d259dd6..f4a5e45eb5f7 100644 --- a/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj +++ b/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj @@ -7,10 +7,7 @@ netcoreapp3.0 Components.E2ETests - - true + true false diff --git a/src/Components/test/testassets/BasicTestApp/wwwroot/index.html b/src/Components/test/testassets/BasicTestApp/wwwroot/index.html index 78540221c380..249622c96e84 100644 --- a/src/Components/test/testassets/BasicTestApp/wwwroot/index.html +++ b/src/Components/test/testassets/BasicTestApp/wwwroot/index.html @@ -5,33 +5,39 @@ Basic test app + + + - Loading... + Loading... + + + - - + - (function () { - // Load either blazor.webassembly.js or blazor.server.js depending - // on the hash part of the URL. This is just to give a way for the - // test runner to make the selection. - var src = location.hash === '#server' - ? 'blazor.server.js' - : 'blazor.webassembly.js'; - document.write(' + + diff --git a/src/Components/test/testassets/TestContentPackage/TestContentPackage.csproj b/src/Components/test/testassets/TestContentPackage/TestContentPackage.csproj index d92a0306a707..934021baca07 100644 --- a/src/Components/test/testassets/TestContentPackage/TestContentPackage.csproj +++ b/src/Components/test/testassets/TestContentPackage/TestContentPackage.csproj @@ -4,19 +4,9 @@ netstandard2.0 library 3.0 + _content/TestContentPackage - - - - - - - - - - - diff --git a/src/Components/test/testassets/TestContentPackage/content/face.png b/src/Components/test/testassets/TestContentPackage/wwwroot/face.png similarity index 100% rename from src/Components/test/testassets/TestContentPackage/content/face.png rename to src/Components/test/testassets/TestContentPackage/wwwroot/face.png diff --git a/src/Components/test/testassets/TestContentPackage/content/prompt.js b/src/Components/test/testassets/TestContentPackage/wwwroot/prompt.js similarity index 100% rename from src/Components/test/testassets/TestContentPackage/content/prompt.js rename to src/Components/test/testassets/TestContentPackage/wwwroot/prompt.js diff --git a/src/Components/test/testassets/TestContentPackage/content/styles.css b/src/Components/test/testassets/TestContentPackage/wwwroot/styles.css similarity index 100% rename from src/Components/test/testassets/TestContentPackage/content/styles.css rename to src/Components/test/testassets/TestContentPackage/wwwroot/styles.css diff --git a/src/Components/test/testassets/TestServer/Program.cs b/src/Components/test/testassets/TestServer/Program.cs index fc2a4d4d2e42..4dfe30322a81 100644 --- a/src/Components/test/testassets/TestServer/Program.cs +++ b/src/Components/test/testassets/TestServer/Program.cs @@ -19,6 +19,7 @@ public static IWebHost BuildWebHost(string[] args) where TStartup : cl .AddCommandLine(args) .Build()) .UseStartup() + .UseStaticWebAssets() .Build(); } } diff --git a/src/Components/test/testassets/TestServer/Startup.cs b/src/Components/test/testassets/TestServer/Startup.cs index 0075a8dfac76..37172cfd6261 100644 --- a/src/Components/test/testassets/TestServer/Startup.cs +++ b/src/Components/test/testassets/TestServer/Startup.cs @@ -1,10 +1,7 @@ using BasicTestApp; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Components.Server; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -63,6 +60,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) // Mount the server-side Blazor app on /subdir app.Map("/subdir", subdirApp => { + subdirApp.UseStaticFiles(); subdirApp.UseClientSideBlazorFiles(); subdirApp.UseRouting(); diff --git a/src/DefaultBuilder/src/WebHost.cs b/src/DefaultBuilder/src/WebHost.cs index a360c89e7fa3..c372114540b0 100644 --- a/src/DefaultBuilder/src/WebHost.cs +++ b/src/DefaultBuilder/src/WebHost.cs @@ -211,7 +211,7 @@ internal static void ConfigureWebDefaults(IWebHostBuilder builder) { if (ctx.HostingEnvironment.IsDevelopment()) { - StaticWebAssetsLoader.UseStaticWebAssets(ctx.HostingEnvironment); + StaticWebAssetsLoader.UseStaticWebAssets(ctx.HostingEnvironment, ctx.Configuration); } }); builder.UseKestrel((builderContext, options) => diff --git a/src/Hosting/Abstractions/ref/Microsoft.AspNetCore.Hosting.Abstractions.netcoreapp3.0.cs b/src/Hosting/Abstractions/ref/Microsoft.AspNetCore.Hosting.Abstractions.netcoreapp3.0.cs index 0da29eccab17..4a3b8668f124 100644 --- a/src/Hosting/Abstractions/ref/Microsoft.AspNetCore.Hosting.Abstractions.netcoreapp3.0.cs +++ b/src/Hosting/Abstractions/ref/Microsoft.AspNetCore.Hosting.Abstractions.netcoreapp3.0.cs @@ -121,6 +121,7 @@ public static partial class WebHostDefaults public static readonly string ServerUrlsKey; public static readonly string ShutdownTimeoutKey; public static readonly string StartupAssemblyKey; + public static readonly string StaticWebAssetsKey; public static readonly string SuppressStatusMessagesKey; public static readonly string WebRootKey; } diff --git a/src/Hosting/Abstractions/src/WebHostDefaults.cs b/src/Hosting/Abstractions/src/WebHostDefaults.cs index 4de391d0a28b..b6fdb728a253 100644 --- a/src/Hosting/Abstractions/src/WebHostDefaults.cs +++ b/src/Hosting/Abstractions/src/WebHostDefaults.cs @@ -21,5 +21,6 @@ public static class WebHostDefaults public static readonly string SuppressStatusMessagesKey = "suppressStatusMessages"; public static readonly string ShutdownTimeoutKey = "shutdownTimeoutSeconds"; + public static readonly string StaticWebAssetsKey = "staticWebAssets"; } } diff --git a/src/Hosting/Hosting/ref/Microsoft.AspNetCore.Hosting.netcoreapp3.0.cs b/src/Hosting/Hosting/ref/Microsoft.AspNetCore.Hosting.netcoreapp3.0.cs index 552830fa07b1..0ecc1a7c3bee 100644 --- a/src/Hosting/Hosting/ref/Microsoft.AspNetCore.Hosting.netcoreapp3.0.cs +++ b/src/Hosting/Hosting/ref/Microsoft.AspNetCore.Hosting.netcoreapp3.0.cs @@ -82,7 +82,7 @@ namespace Microsoft.AspNetCore.Hosting.StaticWebAssets public partial class StaticWebAssetsLoader { public StaticWebAssetsLoader() { } - public static void UseStaticWebAssets(Microsoft.AspNetCore.Hosting.IWebHostEnvironment environment) { } + public static void UseStaticWebAssets(Microsoft.AspNetCore.Hosting.IWebHostEnvironment environment, Microsoft.Extensions.Configuration.IConfiguration configuration) { } } } namespace Microsoft.Extensions.Hosting diff --git a/src/Hosting/Hosting/src/StaticWebAssets/StaticWebAssetsLoader.cs b/src/Hosting/Hosting/src/StaticWebAssets/StaticWebAssetsLoader.cs index 116c9b0cae23..54f8de9b13d9 100644 --- a/src/Hosting/Hosting/src/StaticWebAssets/StaticWebAssetsLoader.cs +++ b/src/Hosting/Hosting/src/StaticWebAssets/StaticWebAssetsLoader.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Reflection; using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.FileProviders; namespace Microsoft.AspNetCore.Hosting.StaticWebAssets @@ -21,10 +22,11 @@ public class StaticWebAssetsLoader /// /// Configure the to use static web assets. /// - /// - public static void UseStaticWebAssets(IWebHostEnvironment environment) + /// The application . + /// The host . + public static void UseStaticWebAssets(IWebHostEnvironment environment, IConfiguration configuration) { - using (var manifest = ResolveManifest(environment)) + using (var manifest = ResolveManifest(environment, configuration)) { if (manifest != null) { @@ -54,13 +56,13 @@ internal static void UseStaticWebAssetsCore(IWebHostEnvironment environment, Str } } - internal static Stream ResolveManifest(IWebHostEnvironment environment) + internal static Stream ResolveManifest(IWebHostEnvironment environment, IConfiguration configuration) { try { - - var assembly = Assembly.Load(environment.ApplicationName); - var filePath = Path.Combine(Path.GetDirectoryName(GetAssemblyLocation(assembly)), $"{environment.ApplicationName}.StaticWebAssets.xml"); + var manifestPath = configuration.GetValue(WebHostDefaults.StaticWebAssetsKey); + var filePath = manifestPath ?? ResolveRelativeToAssembly(environment); + if (File.Exists(filePath)) { return File.OpenRead(filePath); @@ -79,6 +81,12 @@ internal static Stream ResolveManifest(IWebHostEnvironment environment) } } + private static string ResolveRelativeToAssembly(IWebHostEnvironment environment) + { + var assembly = Assembly.Load(environment.ApplicationName); + return Path.Combine(Path.GetDirectoryName(GetAssemblyLocation(assembly)), $"{environment.ApplicationName}.StaticWebAssets.xml"); + } + internal static string GetAssemblyLocation(Assembly assembly) { if (Uri.TryCreate(assembly.CodeBase, UriKind.Absolute, out var result) && diff --git a/src/Hosting/Hosting/src/WebHostBuilderExtensions.cs b/src/Hosting/Hosting/src/WebHostBuilderExtensions.cs index 4541b44ca86b..9189786b1f90 100644 --- a/src/Hosting/Hosting/src/WebHostBuilderExtensions.cs +++ b/src/Hosting/Hosting/src/WebHostBuilderExtensions.cs @@ -189,7 +189,7 @@ public static IWebHostBuilder UseStaticWebAssets(this IWebHostBuilder builder) { builder.ConfigureAppConfiguration((context, configBuilder) => { - StaticWebAssetsLoader.UseStaticWebAssets(context.HostingEnvironment); + StaticWebAssetsLoader.UseStaticWebAssets(context.HostingEnvironment, context.Configuration); }); return builder; diff --git a/src/Hosting/Hosting/test/StaticWebAssets/StaticWebAssetsLoaderTests.cs b/src/Hosting/Hosting/test/StaticWebAssets/StaticWebAssetsLoaderTests.cs index 62f9adaae63e..22ccacef5028 100644 --- a/src/Hosting/Hosting/test/StaticWebAssets/StaticWebAssetsLoaderTests.cs +++ b/src/Hosting/Hosting/test/StaticWebAssets/StaticWebAssetsLoaderTests.cs @@ -2,10 +2,13 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Hosting; using Xunit; namespace Microsoft.AspNetCore.Hosting.StaticWebAssets @@ -72,12 +75,39 @@ public void ResolveManifest_ManifestFromFile() }; // Act - var manifest = StaticWebAssetsLoader.ResolveManifest(environment); + var manifest = StaticWebAssetsLoader.ResolveManifest(environment, new ConfigurationBuilder().Build()); // Assert Assert.Equal(expectedManifest, new StreamReader(manifest).ReadToEnd()); } + [Fact] + public void ResolveManifest_UsesConfigurationKey_WhenProvided() + { + // Arrange + var expectedManifest = @" + + +"; + var path = Path.ChangeExtension(new Uri(typeof(StaticWebAssetsLoader).Assembly.CodeBase).LocalPath, ".StaticWebAssets.xml"); + var environment = new HostingEnvironment() + { + ApplicationName = "NonExistingDll" + }; + + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary() { + [WebHostDefaults.StaticWebAssetsKey] = path + }).Build(); + + // Act + var manifest = StaticWebAssetsLoader.ResolveManifest(environment, configuration); + + // Assert + Assert.Equal(expectedManifest, new StreamReader(manifest).ReadToEnd()); + } + + private Stream CreateManifest(string manifestContent) { return new MemoryStream(Encoding.UTF8.GetBytes(manifestContent)); diff --git a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/React-CSharp/ClientApp/src/components/FetchData.js b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/React-CSharp/ClientApp/src/components/FetchData.js index 3e3a1f3c2101..4782540e3b0a 100644 --- a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/React-CSharp/ClientApp/src/components/FetchData.js +++ b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/React-CSharp/ClientApp/src/components/FetchData.js @@ -28,8 +28,8 @@ export class FetchData extends Component { {forecasts.map(forecast => - - {forecast.dateFormatted} + + {forecast.date} {forecast.temperatureC} {forecast.temperatureF} {forecast.summary} diff --git a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/ClientApp/src/components/FetchData.tsx b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/ClientApp/src/components/FetchData.tsx index cdd33205efbe..c177f0bc6777 100644 --- a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/ClientApp/src/components/FetchData.tsx +++ b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/ClientApp/src/components/FetchData.tsx @@ -52,8 +52,8 @@ class FetchData extends React.PureComponent { {this.props.forecasts.map((forecast: WeatherForecastsStore.WeatherForecast) => - - {forecast.dateFormatted} + + {forecast.date} {forecast.temperatureC} {forecast.temperatureF} {forecast.summary} diff --git a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/ClientApp/src/store/WeatherForecasts.ts b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/ClientApp/src/store/WeatherForecasts.ts index 97e53ff86f08..7648f68b6b92 100644 --- a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/ClientApp/src/store/WeatherForecasts.ts +++ b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/ClientApp/src/store/WeatherForecasts.ts @@ -11,7 +11,7 @@ export interface WeatherForecastsState { } export interface WeatherForecast { - dateFormatted: string; + date: string; temperatureC: number; temperatureF: number; summary: string; diff --git a/src/ProjectTemplates/build.cmd b/src/ProjectTemplates/build.cmd index 2406296662e9..35fb6cc3a3be 100644 --- a/src/ProjectTemplates/build.cmd +++ b/src/ProjectTemplates/build.cmd @@ -1,3 +1,3 @@ @ECHO OFF SET RepoRoot=%~dp0..\.. -%RepoRoot%\build.cmd -projects %~dp0**\*.*proj %* +%RepoRoot%\build.cmd -projects %~dp0**\*.*proj "/p:EnforceE2ETestPrerequisites=true" %* diff --git a/src/ProjectTemplates/build.sh b/src/ProjectTemplates/build.sh index 7046bb98a0fc..fa8fecd0e01f 100755 --- a/src/ProjectTemplates/build.sh +++ b/src/ProjectTemplates/build.sh @@ -4,4 +4,4 @@ set -euo pipefail DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" repo_root="$DIR/../.." -"$repo_root/build.sh" --projects "$DIR/**/*.*proj" "$@" +"$repo_root/build.sh" --projects "$DIR/**/*.*proj" "/p:EnforceE2ETestPrerequisites=true" "$@" diff --git a/src/ProjectTemplates/test/Helpers/Project.cs b/src/ProjectTemplates/test/Helpers/Project.cs index a03abf07bc00..e7b3c4b2b6c1 100644 --- a/src/ProjectTemplates/test/Helpers/Project.cs +++ b/src/ProjectTemplates/test/Helpers/Project.cs @@ -184,7 +184,8 @@ internal AspNetProcess StartBuiltProjectAsync(bool hasListeningUri = true) var environment = new Dictionary { ["ASPNETCORE_URLS"] = _urls, - ["ASPNETCORE_ENVIRONMENT"] = "Development" + ["ASPNETCORE_ENVIRONMENT"] = "Development", + ["ASPNETCORE_Kestrel__EndpointDefaults__Protocols"] = "Http1" }; var projectDll = Path.Combine(TemplateBuildDir, $"{ProjectName}.dll"); @@ -196,6 +197,7 @@ internal AspNetProcess StartPublishedProjectAsync(bool hasListeningUri = true) var environment = new Dictionary { ["ASPNETCORE_URLS"] = _urls, + ["ASPNETCORE_Kestrel__EndpointDefaults__Protocols"] = "Http1" }; var projectDll = $"{ProjectName}.dll"; diff --git a/src/Shared/E2ETesting/BrowserFixture.cs b/src/Shared/E2ETesting/BrowserFixture.cs index c93e618590ed..3efdbdc85bef 100644 --- a/src/Shared/E2ETesting/BrowserFixture.cs +++ b/src/Shared/E2ETesting/BrowserFixture.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Concurrent; +using System.Diagnostics; using System.Linq; using System.Reflection; using System.Threading.Tasks; @@ -78,7 +79,10 @@ public async Task DisposeAsync() var opts = new ChromeOptions(); // Comment this out if you want to watch or interact with the browser (e.g., for debugging) - opts.AddArgument("--headless"); + if (!Debugger.IsAttached) + { + opts.AddArgument("--headless"); + } // Log errors opts.SetLoggingPreference(LogType.Browser, LogLevel.All); diff --git a/src/Shared/E2ETesting/E2ETesting.props b/src/Shared/E2ETesting/E2ETesting.props index 8d9920f2696c..1926e4e57bf4 100644 --- a/src/Shared/E2ETesting/E2ETesting.props +++ b/src/Shared/E2ETesting/E2ETesting.props @@ -3,8 +3,16 @@ <_DefaultProjectFilter>$(MSBuildProjectDirectory)\..\.. $(DefaultItemExcludes);node_modules\** $([MSBuild]::EnsureTrailingSlash('$(RepoRoot)'))artifacts\tmp\selenium\ - true - true + true + + + true + + + true + + + false false diff --git a/src/Shared/E2ETesting/E2ETesting.targets b/src/Shared/E2ETesting/E2ETesting.targets index 648bdae66369..fb3c80a3a381 100644 --- a/src/Shared/E2ETesting/E2ETesting.targets +++ b/src/Shared/E2ETesting/E2ETesting.targets @@ -7,7 +7,7 @@ - @@ -17,13 +17,13 @@ + Condition="'$(SeleniumE2ETestsSupported)' != 'true'"> - + <_PackageJson>$(MSBuildProjectDirectory)\package.json diff --git a/src/Shared/E2ETesting/SeleniumStandaloneServer.cs b/src/Shared/E2ETesting/SeleniumStandaloneServer.cs index 14b92e562488..d62b3ffb0012 100644 --- a/src/Shared/E2ETesting/SeleniumStandaloneServer.cs +++ b/src/Shared/E2ETesting/SeleniumStandaloneServer.cs @@ -30,7 +30,7 @@ public class SeleniumStandaloneServer : IDisposable private static IMessageSink _diagnosticsMessageSink; // 1h 30 min - private static int SeleniumProcessTimeout = 5400; + private static int SeleniumProcessTimeout = 3600; public SeleniumStandaloneServer(IMessageSink diagnosticsMessageSink) { @@ -64,13 +64,9 @@ private void Initialize( public static async Task GetInstanceAsync(ITestOutputHelper output) { - await _semaphore.WaitAsync(); try { - if (Instance == null) - { - - } + await _semaphore.WaitAsync(); if (Instance._process == null) { // No process was started, meaning the instance wasn't initialized. @@ -139,7 +135,7 @@ private static async Task InitializeInstance(ITestOutputHelper output) process.BeginErrorReadLine(); // The Selenium sever has to be up for the entirety of the tests and is only shutdown when the application (i.e. the test) exits. - AppDomain.CurrentDomain.ProcessExit += (sender, args) => ProcessCleanup(process, pidFilePath); + // AppDomain.CurrentDomain.ProcessExit += (sender, args) => ProcessCleanup(process, pidFilePath); // Log void LogOutput(object sender, DataReceivedEventArgs e) @@ -183,7 +179,7 @@ void LogOutput(object sender, DataReceivedEventArgs e) output = null; logOutput.CompleteAdding(); var exitCodeString = process.HasExited ? process.ExitCode.ToString() : "Process has not yet exited."; - var message = @$"Failed to launch the server. + var message = $@"Failed to launch the server. ExitCode: {exitCodeString} Captured output lines: {string.Join(Environment.NewLine, logOutput.GetConsumingEnumerable())}."; @@ -211,19 +207,20 @@ private static Process StartSentinelProcess(Process process, string sentinelFile private static void ProcessCleanup(Process process, string pidFilePath) { - if (process?.HasExited == false) + try { - try - { - process?.KillTree(TimeSpan.FromSeconds(10)); - process?.Dispose(); - } - catch + if (process?.HasExited == false) { + try + { + process?.KillTree(TimeSpan.FromSeconds(10)); + process?.Dispose(); + } + catch + { + // Ignore errors here since we can't do anything + } } - } - try - { if (pidFilePath != null && File.Exists(pidFilePath)) { File.Delete(pidFilePath); @@ -231,6 +228,7 @@ private static void ProcessCleanup(Process process, string pidFilePath) } catch { + // Ignore errors here since we can't do anything } }