Szenario
I want to build an aspnetcore library/module that includes a small SPA frontend. I.e. the html/js/css files should come along with the dll.
The SPA should be served from a specific path, i.e. /some-module (does not need to be configurable).
The SPA consists of several html/js/css files, lets assume following files:
/my-module/index.html
/my-module/index.js
/my-module/index.css
These urls should just server the files. all other paths such as
/my-module/
/my-module/page-1
/my-module/page-2
should serve the index.html, so that client-side routing can handle the requests.
I have a partial solution, where the SPA files are served. However I don't know how to make all other subpaths i.e. /my-module/* (excluding the files) to return index.html.
Partial Solution using embedded files and UseFileServer:
Assuming the SPA build files are located in /my-library/web/build/. The following csproj embeds these files into the dll using GenerateEmbeddedFilesManifest and EmbeddedResource:
my-module.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
<SpaRoot>web\</SpaRoot>
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
</PropertyGroup>
<ItemGroup>
<Folder Include="web\" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="web\build\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
</ItemGroup>
</Project>
The following middleware configuration serves these embedded files using the ManifestEmbeddedFileProvider:
public static void UseMyModuleUi(this IApplicationBuilder app)
{
app.UseFileServer(new FileServerOptions
{
RequestPath = "/my-module",
FileProvider = new ManifestEmbeddedFileProvider(
assembly: Assembly.GetAssembly(typeof(ServiceExtensions)), "web/build")
});
}
Calling the UseMyModuleUi extension method in some aspnetcore application that references my module, this does indeed serve the files under
/my-module/index.html
/my-module/index.js
/my-module/index.css
even /my-module/ serves my-module/index.html.
However all other paths under /my-module/ such as my-module/page-1 do not serve index.html.#
Alternatives I tried
I tried to use some combinations of UseSpaStaticFiles or UseStaticFiles and Map, however with no good results.
The project I am build is available here: https://github.com/jannikbuschke/ef-configuration-provider
the ui project is the library that embedds a SPA. The sample project is the host application.
The following should work for you:
Mapdefines a new branch that gets executed when the request starts with the given path and removes that path segment from the for this branch.ManifestEmbeddedFileProviderindex.htmlfor every non-matching request,Rundefines a delegate that always returns the given file. Thats your so called catch-all for this branch.