In .NET 6.0 we are changing the way the SPA templates work to leverage the built-in development server proxy these frameworks ship instead of proxying requests from ASP.NET Core to the proxy backends.
The current proxy approach is non-standard, requires us to have runtime support and is the cause of a high number of issues that we don't have the resources to tackle and that lead to a bad experience for our customers.
- Use a standard approach for working with SPA applications in ASP.NET Core.
- Leverage tooling and elements from the existing SPA frameworks.
- Maintain as close as an experience to the current development experience:
- Support HTTPs on the different SPA frameworks leveraging the ASP.NET Core HTTPS certificate.
- Support a single gesture launch experience with dotnet run.
- Remove runtime support code at development and production time to make sure we are never a blocking factor for our customers.
- All aspects of how the SPA proxy runs and is launched can be customized via the project settings or the template files.
- As a developer I want to launch my ASP.NET Core and SPA front-end via
dotnet run
.- HTTPS for the given framework (react/angular) is configured automatically.
- HTTP requests are routed to the backend API.
- As a developer I want to launch my SPA front-end and have it use the same port and certificate it uses when launched from VS or via
dotnet run
. - As a developer I want to launch my ASP.NET Core and SPA front-end with
F5
in Visual Studio. - As a developer I want to launch my ASP.NET Core and SPA front-end with
F5
in Visual Studio for Mac.
- Configuring API urls for the proxy is a manual process (although we can try and smooth it to be a "one time thing").
- Switching between kestrel/iis requires changing the target url in proxy.conf.json
- Process management: If we are not careful, some processes can be left behind.
- For users running manually or via CLI, we can make them aware of this fact and have them cleanup if necessary.
- The fact that the proxy might already be running doesn't generally lead to errors.
- For users running via Visual Studio we will bypass this problem all-together when the proxy is launched by VS instead of our support.
- For users running manually or via CLI, we can make them aware of this fact and have them cleanup if necessary.
- Integration with IIS: When the app is launched via IIS, it opens the proxy launch url. However the app is not actually launched until you hit a url in the backend, which only ever happens, which normally only happens when the SPA triggers a request to the backend. Given that in development the backend is responsible for starting the proxy, this causes an issue since the backend in not started and can't start the proxy.
We tried to maintain the current experience as much as possible and making the new experience as friendly as possible to existing customers and to future improvements where we leverage create-react-app, ng new, and similar CLIs to create the application.
In addition to the existing files on the template there are a few more files that we are adding:
- proxy.conf.json -> Takes care of configuring the SPA dev server to proxy requests to the backend. It's standard across all/most front-end frameworks since they leverage webpack-dev-server under the hood.
- aspnetcore-https.js -> This script takes care of exporting the ASP.NET Core HTTPS development certificate in a format that the SPA framework can consume.
- It follows the same approach as docker, where it puts the certificate in a special location outside of the scope of the project to avoid accidentally checking it in.
- aspnetcore-react -> This script is specific to react and takes care of setting up
.env.development.local
to use the ASP.NET Core certificate, the port and the proxy.config.json files that make the integration with the backend anddotnet run
experience possible. - package.json:
- For react, we add a "prestart" script that invokes aspnetcore-https and aspnetcore-react to make sure everything is setup.
- For angular, we add a "prestart" script to invoke aspnetcore-https and we use
run-script-os
(new dependency) to launch the app with the correct parameters across different OSs.
- We remove all the SPA specific code from startup since it is no longer needed.
- We switch publish from
dist
towwwroot
for the SPA files and they get served via the static files middleware. - We add
endpoint.MapFallbackToFile("index.html")
to map unknown requests to the index.html.
- We have a support library that is plugged in during development via a hosting startup assembly we define in launchSettings.json `"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "<>".
- This assembly checks for the existence of a spa.proxy.json file and adds a hosted service that is responsible for managing the proxy when found.
- At build time, we generate the spa.proxy.json file that gets copied to the build output and that contains the following information:
- ProbeUrl: We use this URL to determine the front-end proxy is ready running and avoid launching it in that case.
- LaunchCommand: We use this command to launch the proxy from the process if we determine the proxy is not running.
- MaxTimeoutInSeconds: The amount of time to wait before giving up and producing an error.
- Our hosted service tries to determine if the proxy is already running and does nothing in that case.
- Otherwise, it tries to start a new instance of the proxy and after it does so, it probes the ProbeUrl until it receives a successful response.
- The command used to launch the proxy is configurable via MSBuild parameters, by default they do the following:
cmd /c npm/yarn start
on Windows./bin/bash -c npm/yarn start
on Mac/Linux.
- If this doesn't work for a given user they can adjust it for their environment.
- We aim for this to work 99% of the time and for the majority of scenarios, but for the cases where it doesn't. Our answer is two-fold:
- Disable it by removing the package/value from launchSettings.json
- Adjust the command to suit your needs.