Procházet zdrojové kódy

Custom middleware for handling SPA default page

Lukas Angerer před 3 roky
rodič
revize
adb1675762

+ 3 - 8
src/RunnersMeet.Server/AppServer.cs

@@ -1,6 +1,7 @@
 using Microsoft.AspNetCore.Authentication.JwtBearer;
 using Microsoft.AspNetCore.StaticFiles.Infrastructure;
 using Microsoft.IdentityModel.Tokens;
+using RunnersMeet.Server.Frontend;
 using RunnersMeet.Server.GpxFormat;
 using RunnersMeet.Server.Persistence;
 
@@ -65,17 +66,11 @@ public class AppServer
 		app.UseHttpsRedirection();
 		app.UseCors();
 		app.UseAuthorization();
-		app.UseDefaultFiles(new DefaultFilesOptions()
-		{
-			DefaultFileNames = new List<string>
-			{
-				"index.html"
-			}
-		});
+		app.UseSpaDefaultPageMiddleware();
 		app.UseStaticFiles();
-
 		app.MapControllers();
 
+
 		app.Run();
 	}
 

+ 11 - 0
src/RunnersMeet.Server/Frontend/SpaDefaultPageConfig.cs

@@ -0,0 +1,11 @@
+namespace RunnersMeet.Server.Frontend;
+
+public class SpaDefaultPageConfig
+{
+	public string DefaultPage { get; set; }
+
+	public SpaDefaultPageConfig()
+	{
+		DefaultPage = "/index.html";
+	}
+}

+ 41 - 0
src/RunnersMeet.Server/Frontend/SpaDefaultPageMiddleware.cs

@@ -0,0 +1,41 @@
+using Microsoft.Extensions.FileProviders;
+using Microsoft.Extensions.Options;
+
+namespace RunnersMeet.Server.Frontend;
+
+public class SpaDefaultPageMiddleware
+{
+	private readonly RequestDelegate _next;
+	private readonly IFileProvider _fileProvider;
+	private readonly IOptions<SpaDefaultPageConfig> _defaultPageOptions;
+
+	public SpaDefaultPageMiddleware(
+		RequestDelegate next,
+		IOptions<StaticFileOptions> staticFileOptions,
+		IOptions<SpaDefaultPageConfig> defaultPageOptions,
+		IWebHostEnvironment hostingEnvironment)
+	{
+		_next = next;
+		_fileProvider = staticFileOptions.Value.FileProvider ?? hostingEnvironment.WebRootFileProvider;
+		_defaultPageOptions = defaultPageOptions;
+	}
+
+	public async Task InvokeAsync(HttpContext context)
+	{
+		// See https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/Spa/SpaServices.Extensions/src/SpaDefaultPageMiddleware.cs
+		// where this is mostly borrowed from - in combination with the Microsoft.AspNetCore.StaticFiles.DefaultFilesMiddleware code.
+		if (HttpMethods.IsGet(context.Request.Method) && context.GetEndpoint() == null)
+		{
+			// StaticFileMiddleware comes _after_ this middleware, so we use the file provider that is used by
+			// the static file middleware to figure out ahead of time if there is actually a file matching the
+			// request path and if not, we just "re-target" the request to our default page.
+			var fileInfo = _fileProvider.GetFileInfo(context.Request.Path);
+			if (!fileInfo.Exists)
+			{
+				context.Request.Path = _defaultPageOptions.Value.DefaultPage;
+			}
+		}
+
+		await _next(context);
+	}
+}

+ 9 - 0
src/RunnersMeet.Server/Frontend/SpaDefaultPageMiddlewareExtensions.cs

@@ -0,0 +1,9 @@
+namespace RunnersMeet.Server.Frontend;
+
+public static class SpaDefaultPageMiddlewareExtensions
+{
+	public static IApplicationBuilder UseSpaDefaultPageMiddleware(this IApplicationBuilder builder)
+	{
+		return builder.UseMiddleware<SpaDefaultPageMiddleware>();
+	}
+}