Server-side rendering in ASP.NET Core Angular (2024 version)
This is an updated version of following walkthrough.
Create the project
Start by creating a new ASP.NET Core project. Choose the Web API template:
If you wish to use the Visual Studio publish wizard, try putting your project as close to the drive root as possible (Yes, you’re right, Visual Studio 2022 still doesn’t support the LongPathApi…)
Off course we choose to use .NET 8
Make sure you have the latest version of angular installed. Run a cmd as administrator, and issue:
npm install --global @angular/cli@latest
ng version
> 17.0.3
Now we’ll create the ClientApp by running the following command from the project folder:
ng new ClientApp --style scss --routing --ssr=false
We’re not yet adding SSR here.
.NET Setup
- Open the NuGet package manager and install
MintPlayer.AspNetCore.Hsts
. This is an improved version of the ASP.NET Core HSTS Middleware, which works correctly for SPA’s. This middleware uses theOnStarting
callback, and effectively adds the header to the HTTP response when visiting any page in your angular application. - Also install the
MintPlayer.AspNetCore.SpaServices.Routing
package into your project. This package contains the RouteBuilder to parse visited urls in your backend. The dependency projectPrerendering
contains the SpaPrerendering middleware.
Add the following Program class
The only thing missing now is the SpaPrerenderingService
This service is registered as a scoped service, so you can inject repositories, DbContext through the constructor.
Modify your csproj file. Best bet is to just copy below:
Angular setup
Edit the angular.json
and add below snippet inside the projects:ClientApp:architect
section:
As you can see we need to add a tsconfig.server.json
and main.server.ts
file
Now install the additional packages
npm i aspnet-prerendering
npm i @angular/platform-server
Create the following file:
Add some scripts to your package.json
Now the output
folder is still disconfigured, and the configuration won’t work when DOTNET_ENVIRONMENT = Production
. To fix this, open the angular.json
file and change the outputPath
from dist/client-app
to just dist
.
Modify the main.ts:
tsconfig.app.json
The result is here: https://github.com/PieterjanDeClippel/Ssr/tree/master
EDIT
Since the .NET template was updated by Microsoft, you need to make additional changes before starting the deployment to your live webserver.
Html Minification
- Open the NuGet package manager, and install
WebMarkupMin.AspNetCore8
- Update the
Program.cs
Result:
Localization
npm i @ngx-translate/http-loader
Now we can setup the TranslateModule
in both the browser and server module
At last add the "resolveJsonModule": true
to the tsconfig.json under compilerOptions
Add the message to app.component.html
:
<h1>{{ 'greeting' | translate }}, {{ title }}</h1>
And put 2 links at the bottom of the app component to navigate
Supplying data
Let’s send an object from .NET to angular during SSR. This object can be one fetched from the database whilst on the server.
In the main.server.ts
we passed the entire params.data
to a provider. We can now inject it and use it on the app component:
We need to update the DataFromServer
interface
Now let’s show this information on the app component:
TransferState
There are 3 possible scenarios you can implement here:
- Retrieve the data on the server, use
OnSupplyData
to pass to angular — During client-side-rendering send another HTTP request to retrieve the same data - Retrieve the data on the server, use
OnSupplyData
to pass to angular — In angular during server-side-rendering put the data into theTransferState
, and read it during client-side-rendering ← Focus on this - Use the new client-hydration feature with HTTP-caching in angular. In this scenario, the app is rendered on the server, sends HTTP requests to the API, these requests and responses are stored in the
TransferState
, and when the HTTP client is calling the same urls from the browser, the data is read from theTransferState
. I don’t think I can use this feature because my live environment crashes when angular sends ajax calls to my api during SSR
The result is hosted here
Troubleshoot
- Important!!!!: Please check the output window. Half of the information needed to solve occasional problems with SSR is logged in the Visual Studio Output window, so the Visual Studio Output window is the most interesting source to diagnose issues here. If you’re experiencing problems, don’t hesitate to write back, but include the contents of your Output window.
- In previous walkthroughs I’ve written out some checks you can perform to solve several issues