diff --git a/src/Components/Blazor.sln b/src/Components/Blazor.sln
index 8790973228..829fd645e4 100644
--- a/src/Components/Blazor.sln
+++ b/src/Components/Blazor.sln
@@ -552,9 +552,9 @@ Global
{C4D74173-702B-428A-B689-1A9AF51CE356} = {B29FB58D-FAE5-405E-9695-BCF93582BE9A}
{B3EF0C88-3466-40AE-9080-F694370F4192} = {C4D74173-702B-428A-B689-1A9AF51CE356}
{2916EC17-1D1F-4949-9EC7-50725157F1A6} = {C4D74173-702B-428A-B689-1A9AF51CE356}
- {7EFB9CAF-6716-43BF-A6EF-C2878E95F8A6} = {B4ACD900-27B6-482B-B434-2C1E86E9D8BC}
- {194EBC45-F98E-4919-B714-C1624EF17B31} = {B4ACD900-27B6-482B-B434-2C1E86E9D8BC}
- {EAF50654-98ED-44BB-A120-0436EC0CD3E0} = {B4ACD900-27B6-482B-B434-2C1E86E9D8BC}
+ {7EFB9CAF-6716-43BF-A6EF-C2878E95F8A6} = {CBD2BB24-3EC3-4950-ABE4-8C521D258DCD}
+ {194EBC45-F98E-4919-B714-C1624EF17B31} = {CBD2BB24-3EC3-4950-ABE4-8C521D258DCD}
+ {EAF50654-98ED-44BB-A120-0436EC0CD3E0} = {CBD2BB24-3EC3-4950-ABE4-8C521D258DCD}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {27A36094-AA50-4FFD-ADE6-C055E391F741}
diff --git a/src/Components/WebAssembly/DevServer/src/Server/Startup.cs b/src/Components/WebAssembly/DevServer/src/Server/Startup.cs
index 9096edfb0f..84bf7ac852 100644
--- a/src/Components/WebAssembly/DevServer/src/Server/Startup.cs
+++ b/src/Components/WebAssembly/DevServer/src/Server/Startup.cs
@@ -28,8 +28,6 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.DevServer.Server
{
services.AddRouting();
- services.AddWebAssemblyStaticFilesConfiguration();
-
services.AddResponseCompression(options =>
{
options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[]
@@ -54,6 +52,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.DevServer.Server
app.UseEndpoints(endpoints =>
{
+ endpoints.MapBlazorWebAssemblyApplication();
endpoints.MapFallbackToFile("index.html");
});
}
diff --git a/src/Components/WebAssembly/Server/src/ComponentsWebAssemblyEndpointRouteBuilderExtensions.cs b/src/Components/WebAssembly/Server/src/ComponentsWebAssemblyEndpointRouteBuilderExtensions.cs
new file mode 100644
index 0000000000..d29212ff75
--- /dev/null
+++ b/src/Components/WebAssembly/Server/src/ComponentsWebAssemblyEndpointRouteBuilderExtensions.cs
@@ -0,0 +1,111 @@
+// 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.Net.Mime;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Routing;
+using Microsoft.AspNetCore.StaticFiles;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.FileProviders;
+using Microsoft.Net.Http.Headers;
+
+namespace Microsoft.AspNetCore.Builder
+{
+ ///
+ /// Extensions for mapping Blazor WebAssembly applications.
+ ///
+ public static class ComponentsWebAssemblyEndpointRouteBuilderExtensions
+ {
+ ///
+ /// Maps a Blazor webassembly application to the .
+ ///
+ /// The .
+ /// The that indicates the prefix for the Blazor application.
+ /// The
+ public static IEndpointConventionBuilder MapBlazorWebAssemblyApplication(this IEndpointRouteBuilder endpoints, PathString pathPrefix)
+ {
+ if (endpoints is null)
+ {
+ throw new ArgumentNullException(nameof(endpoints));
+ }
+
+ var webHostEnvironment = endpoints.ServiceProvider.GetRequiredService();
+
+ var options = CreateStaticFilesOptions(webHostEnvironment.WebRootFileProvider);
+ var appBuilder = endpoints.CreateApplicationBuilder();
+
+ appBuilder.Use(async (ctx, next) =>
+ {
+ var endpoint = ctx.GetEndpoint();
+ try
+ {
+ // Set the endpoint to null so that static files doesn't discard the path.
+ ctx.SetEndpoint(null);
+
+ if (ctx.Request.Path.StartsWithSegments(pathPrefix, out var rest) &&
+ rest.StartsWithSegments("/_framework"))
+ {
+ // At this point we mapped something from the /_framework
+ ctx.Response.Headers.Append(HeaderNames.CacheControl, "no-cache");
+ }
+
+ // This will invoke the static files middleware plugged-in below.
+ await next();
+
+ }
+ finally
+ {
+ ctx.SetEndpoint(endpoint);
+ }
+ });
+
+ appBuilder.UseStaticFiles(options);
+
+ var conventionBuilder = endpoints.Map(
+ $"{pathPrefix}/{{*path:file}}",
+ appBuilder.Build());
+
+ conventionBuilder.Add(builder =>
+ {
+ // Map this route with low priority so that it doesn't interfere with any other potential request.
+ ((RouteEndpointBuilder)builder).Order = int.MaxValue - 100;
+ });
+
+ return conventionBuilder;
+ }
+
+ ///
+ /// Maps a Blazor webassembly application to the root path of the application "/".
+ ///
+ /// The .
+ /// The that indicates the prefix for the Blazor application.
+ /// The
+ public static IEndpointConventionBuilder MapBlazorWebAssemblyApplication(this IEndpointRouteBuilder endpoints) =>
+ MapBlazorWebAssemblyApplication(endpoints, default);
+
+ private static StaticFileOptions CreateStaticFilesOptions(IFileProvider webRootFileProvider)
+ {
+ var options = new StaticFileOptions();
+ options.FileProvider = webRootFileProvider;
+ var contentTypeProvider = new FileExtensionContentTypeProvider();
+ AddMapping(contentTypeProvider, ".dll", MediaTypeNames.Application.Octet);
+ // We unconditionally map pdbs as there will be no pdbs in the output folder for
+ // release builds unless BlazorEnableDebugging is explicitly set to true.
+ AddMapping(contentTypeProvider, ".pdb", MediaTypeNames.Application.Octet);
+
+ options.ContentTypeProvider = contentTypeProvider;
+
+ return options;
+ }
+
+ private static void AddMapping(FileExtensionContentTypeProvider provider, string name, string mimeType)
+ {
+ if (!provider.Mappings.ContainsKey(name))
+ {
+ provider.Mappings.Add(name, mimeType);
+ }
+ }
+ }
+}
diff --git a/src/Components/WebAssembly/Server/src/Services/ComponentsWebAssemblyServiceCollectionExtensions.cs b/src/Components/WebAssembly/Server/src/Services/ComponentsWebAssemblyServiceCollectionExtensions.cs
deleted file mode 100644
index 07c95c063f..0000000000
--- a/src/Components/WebAssembly/Server/src/Services/ComponentsWebAssemblyServiceCollectionExtensions.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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.Net.Mime;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.AspNetCore.StaticFiles;
-using Microsoft.Extensions.DependencyInjection.Extensions;
-using Microsoft.Extensions.Options;
-
-namespace Microsoft.Extensions.DependencyInjection
-{
- public static class ComponentsWebAssemblyServiceCollectionExtensions
- {
- public static IServiceCollection AddWebAssemblyStaticFilesConfiguration(this IServiceCollection services)
- {
- services.TryAddEnumerable(ServiceDescriptor.Singleton, ClientSideBlazorStaticFilesConfiguration>());
- return services;
- }
-
- private class ClientSideBlazorStaticFilesConfiguration : IConfigureOptions
- {
- private readonly IWebHostEnvironment _webHostEnvironment;
-
- public ClientSideBlazorStaticFilesConfiguration(IWebHostEnvironment webHostEnvironment)
- {
- _webHostEnvironment = webHostEnvironment;
- }
-
- public void Configure(StaticFileOptions options)
- {
- options.FileProvider = _webHostEnvironment.WebRootFileProvider;
- var contentTypeProvider = new FileExtensionContentTypeProvider();
- AddMapping(contentTypeProvider, ".dll", MediaTypeNames.Application.Octet);
- // We unconditionally map pdbs as there will be no pdbs in the output folder for
- // release builds unless BlazorEnableDebugging is explicitly set to true.
- AddMapping(contentTypeProvider, ".pdb", MediaTypeNames.Application.Octet);
-
- options.ContentTypeProvider = contentTypeProvider;
- }
-
- private static void AddMapping(FileExtensionContentTypeProvider provider, string name, string mimeType)
- {
- if (!provider.Mappings.ContainsKey(name))
- {
- provider.Mappings.Add(name, mimeType);
- }
- }
- }
- }
-}
diff --git a/src/Components/WebAssembly/testassets/HostedInAspNet.Server/Startup.cs b/src/Components/WebAssembly/testassets/HostedInAspNet.Server/Startup.cs
index 40bdd6c37c..a605d10ded 100644
--- a/src/Components/WebAssembly/testassets/HostedInAspNet.Server/Startup.cs
+++ b/src/Components/WebAssembly/testassets/HostedInAspNet.Server/Startup.cs
@@ -15,7 +15,6 @@ namespace HostedInAspNet.Server
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton();
- services.AddWebAssemblyStaticFilesConfiguration();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@@ -34,12 +33,11 @@ namespace HostedInAspNet.Server
app.UseBlazorDebugging();
}
- app.UseStaticFiles();
-
app.UseRouting();
app.UseEndpoints(endpoints =>
{
+ endpoints.MapBlazorWebAssemblyApplication();
endpoints.MapFallbackToFile("index.html");
});
}
diff --git a/src/Components/WebAssembly/testassets/MonoSanity/Startup.cs b/src/Components/WebAssembly/testassets/MonoSanity/Startup.cs
index 17f115a565..f777cbc4b3 100644
--- a/src/Components/WebAssembly/testassets/MonoSanity/Startup.cs
+++ b/src/Components/WebAssembly/testassets/MonoSanity/Startup.cs
@@ -10,7 +10,6 @@ namespace MonoSanity
{
public void ConfigureServices(IServiceCollection services)
{
- services.AddWebAssemblyStaticFilesConfiguration();
}
public void Configure(IApplicationBuilder app)
@@ -21,6 +20,7 @@ namespace MonoSanity
app.UseRouting();
app.UseEndpoints(endpoints =>
{
+ endpoints.MapBlazorWebAssemblyApplication();
endpoints.MapFallbackToFile("index.html");
});
}
diff --git a/src/Components/WebAssembly/testassets/Wasm.Authentication.Server/Startup.cs b/src/Components/WebAssembly/testassets/Wasm.Authentication.Server/Startup.cs
index 2e239f07a0..58c8fdb2c1 100644
--- a/src/Components/WebAssembly/testassets/Wasm.Authentication.Server/Startup.cs
+++ b/src/Components/WebAssembly/testassets/Wasm.Authentication.Server/Startup.cs
@@ -37,8 +37,6 @@ namespace Wasm.Authentication.Server
services.AddAuthentication()
.AddIdentityServerJwt();
- services.AddWebAssemblyStaticFilesConfiguration();
-
services.AddMvc();
services.AddResponseCompression(opts =>
{
@@ -58,8 +56,6 @@ namespace Wasm.Authentication.Server
app.UseBlazorDebugging();
}
- app.UseStaticFiles();
-
app.UseRouting();
app.UseAuthentication();
@@ -70,6 +66,8 @@ namespace Wasm.Authentication.Server
{
endpoints.MapControllers();
endpoints.MapRazorPages();
+
+ endpoints.MapBlazorWebAssemblyApplication();
endpoints.MapFallbackToFile("index.html");
});
}
diff --git a/src/Components/test/E2ETest/Tests/BootResourceCachingTest.cs b/src/Components/test/E2ETest/Tests/BootResourceCachingTest.cs
index 941a99c253..7452c30a5f 100644
--- a/src/Components/test/E2ETest/Tests/BootResourceCachingTest.cs
+++ b/src/Components/test/E2ETest/Tests/BootResourceCachingTest.cs
@@ -57,7 +57,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
var subsequentResourcesRequested = GetAndClearRequestedPaths();
Assert.NotEmpty(initialResourcesRequested.Where(path => path.EndsWith("/blazor.boot.json")));
Assert.Empty(subsequentResourcesRequested.Where(path => path.EndsWith("/dotnet.wasm")));
- Assert.Empty(subsequentResourcesRequested.Where(path => path.EndsWith(".js")));
+ Assert.NotEmpty(subsequentResourcesRequested.Where(path => path.EndsWith(".js")));
Assert.Empty(subsequentResourcesRequested.Where(path => path.EndsWith(".dll")));
}
diff --git a/src/Components/test/testassets/TestServer/AuthenticationStartup.cs b/src/Components/test/testassets/TestServer/AuthenticationStartup.cs
index a395dad910..261587c9ee 100644
--- a/src/Components/test/testassets/TestServer/AuthenticationStartup.cs
+++ b/src/Components/test/testassets/TestServer/AuthenticationStartup.cs
@@ -28,8 +28,6 @@ namespace TestServer
services.AddServerSideBlazor();
- services.AddWebAssemblyStaticFilesConfiguration();
-
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();
services.AddAuthorization(options =>
{
@@ -56,6 +54,7 @@ namespace TestServer
app.UseRouting();
app.UseEndpoints(endpoints =>
{
+ endpoints.MapBlazorWebAssemblyApplication();
endpoints.MapControllers();
endpoints.MapRazorPages();
endpoints.MapBlazorHub();
diff --git a/src/Components/test/testassets/TestServer/ClientStartup.cs b/src/Components/test/testassets/TestServer/ClientStartup.cs
index 6381adc921..4d4161b13d 100644
--- a/src/Components/test/testassets/TestServer/ClientStartup.cs
+++ b/src/Components/test/testassets/TestServer/ClientStartup.cs
@@ -23,7 +23,6 @@ namespace TestServer
{
services.AddMvc();
services.AddServerSideBlazor();
- services.AddWebAssemblyStaticFilesConfiguration();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@@ -43,6 +42,8 @@ namespace TestServer
app.UseRouting();
app.UseEndpoints(endpoints =>
{
+ endpoints.MapBlazorWebAssemblyApplication();
+
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
diff --git a/src/Components/test/testassets/TestServer/CorsStartup.cs b/src/Components/test/testassets/TestServer/CorsStartup.cs
index 0ae0a13c8a..c6ed533955 100644
--- a/src/Components/test/testassets/TestServer/CorsStartup.cs
+++ b/src/Components/test/testassets/TestServer/CorsStartup.cs
@@ -19,7 +19,6 @@ namespace TestServer
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
- services.AddWebAssemblyStaticFilesConfiguration();
services.AddCors(options =>
{
// It's not enough just to return "Access-Control-Allow-Origin: *", because
@@ -54,6 +53,8 @@ namespace TestServer
app.UseEndpoints(endpoints =>
{
+ endpoints.MapBlazorWebAssemblyApplication();
+
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
diff --git a/src/Components/test/testassets/TestServer/InternationalizationStartup.cs b/src/Components/test/testassets/TestServer/InternationalizationStartup.cs
index 752778f481..5f19ea80f5 100644
--- a/src/Components/test/testassets/TestServer/InternationalizationStartup.cs
+++ b/src/Components/test/testassets/TestServer/InternationalizationStartup.cs
@@ -23,7 +23,6 @@ namespace TestServer
{
services.AddMvc();
services.AddServerSideBlazor();
- services.AddWebAssemblyStaticFilesConfiguration();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@@ -55,6 +54,8 @@ namespace TestServer
app.UseRouting();
app.UseEndpoints(endpoints =>
{
+ endpoints.MapBlazorWebAssemblyApplication();
+
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_ServerHost");
diff --git a/src/Components/test/testassets/TestServer/StartupWithMapFallbackToClientSideBlazor.cs b/src/Components/test/testassets/TestServer/StartupWithMapFallbackToClientSideBlazor.cs
index 1b30089b16..9097914793 100644
--- a/src/Components/test/testassets/TestServer/StartupWithMapFallbackToClientSideBlazor.cs
+++ b/src/Components/test/testassets/TestServer/StartupWithMapFallbackToClientSideBlazor.cs
@@ -21,7 +21,6 @@ namespace TestServer
public void ConfigureServices(IServiceCollection services)
{
- services.AddWebAssemblyStaticFilesConfiguration();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
@@ -34,7 +33,12 @@ namespace TestServer
// The client-side files middleware needs to be here because the base href in hardcoded to /subdir/
app.Map("/subdir", app =>
{
- app.UseStaticFiles();
+ app.UseRouting();
+
+ app.UseEndpoints(endpoints =>
+ {
+ endpoints.MapBlazorWebAssemblyApplication();
+ });
});
// The calls to `Map` allow us to test each of these overloads, while keeping them isolated.
diff --git a/src/ProjectTemplates/ComponentsWebAssembly.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Server/Startup.cs b/src/ProjectTemplates/ComponentsWebAssembly.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Server/Startup.cs
index 1e2ccb8c5d..85573e7daf 100644
--- a/src/ProjectTemplates/ComponentsWebAssembly.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Server/Startup.cs
+++ b/src/ProjectTemplates/ComponentsWebAssembly.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Server/Startup.cs
@@ -71,8 +71,6 @@ namespace ComponentsWebAssembly_CSharp.Server
services.AddRazorPages();
#endif
- services.AddWebAssemblyStaticFilesConfiguration();
-
services.AddResponseCompression(opts =>
{
opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
@@ -127,6 +125,7 @@ namespace ComponentsWebAssembly_CSharp.Server
#endif
endpoints.MapControllers();
+ endpoints.MapBlazorWebAssemblyApplication();
endpoints.MapFallbackToFile("index.html");
});
}