Reputation: 524
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
.
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
.#
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.
Upvotes: 2
Views: 1394
Reputation: 761
The following should work for you:
public static void UseMyModuleUi(this IApplicationBuilder app)
{
app.Map("/my-module", builder =>
{
var provider = new ManifestEmbeddedFileProvider(
assembly: Assembly.GetAssembly(typeof(ServiceExtensions)), "web/build");
builder.UseStaticFiles(new StaticFileOptions
{
FileProvider = provider
});
builder.Run(async context =>
{
await context.Response.SendFileAsync(provider.GetFileInfo("index.html"));
});
});
}
Map
defines a new branch that gets executed when the request starts with the given path and removes that path segment from the for this branch.ManifestEmbeddedFileProvider
index.html
for every non-matching request, Run
defines a delegate that always returns the given file. Thats your so called catch-all for this branch.Upvotes: 2