Let’s say we have an existing .Net Core web API project that looks like this (this is what the default web API template gives you)

I made a small change in the route prefix so all API endpoints start with path /api

Now, we want to add an SPA to the same project and served at path /dashboard. For this example, we’ll be adding a React app to the web API project.
Firstly, we add a folder named ReactApp in the web API project for the SPA. Then we create the React app in the new folder. I use the following command to create a new React app (see here for more info).
npx create-react-app dashboard
Then, navigate to the new React app and open the package.json file. Change the build script from
"build": "react-scripts build"
to the following if you use Windows
"build": "SET \"PUBLIC_URL=/dashboard\" && react-scripts build",
or the following if you use Linux
"build": "export \"PUBLIC_URL=/dashboard\" && react-scripts build"
Then run ‘yarn build’ to build it. This will create a ‘Build’ folder in the React app root directory. This is the folder we want to copy to the output directory when we build the web API. So we need to add the following in the .csproj file
<ItemGroup>
<None Update="ReactApp\dashboard\build\**\*.*">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
Finally, in the StartUp.cs file, we need to add the following. You might need to install nuget package Microsoft.AspNetCore.SpaServices.Extensions.
public class Startup
{
private const string ReactAppRoot = "ReactApp/dashboard/build";
public void ConfigureServices(IServiceCollection services)
{
// Other configurations go here
services.AddSpaStaticFiles(config => config.RootPath = ReactAppRoot);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// Other configurations go here
// These go late in the chain as recommended here https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.spaapplicationbuilderextensions.usespa?view=aspnetcore-3.0
app.UseSpaStaticFiles(new StaticFileOptions
{
RequestPath = "/dashboard"
});
app.Map(new PathString("/dashboard"), x =>
{
x.UseSpa(spa =>
{
spa.Options.SourcePath = ReactAppRoot;
});
});
}
}
Now, when we run the web API and navigate to /dashboard, we should see the default React app.
