I'm converting my CSR angular app to SSR using .net 6. Now the .net backend is having trouble serving the files for the frontend. All the files build and are correctly placed in the proper directories. See snippets for setup files below. angular.json snippet "server": { "builder": "@angular-devkit/build-angular:server", "options": { "outputPath": "dist/my-app/server", "main": "src/main.server.ts", "tsConfig": "tsconfig.server.json" }, "configurations": { ... } }, "serve-ssr": { "builder": "@angular-devkit/build-angular:ssr-dev-server", "options": { "host": "localhost", "port": 44492, "ssl": true, "sslCert": "%APPDATA%\\ASP.NET\\https\\%npm_package_name%.pem", "sslKey": "%APPDATA%\\ASP.NET\\https\\%npm_package_name%.key", "proxyConfig": "proxy.conf.js" }, "configurations": { "development": { "browserTarget": "my-app:build:development", "serverTarget": "my-app:server:development" }, "production": { "browserTarget": "my-app:buildroduction", "serverTarget": "my-app:serverroduction" } }, "defaultConfiguration": "development" }, tsconfig.server.json snippet { "extends": "./tsconfig.json", "compilerOptions": { "outDir": "./dist/my-app/server", "target": "es2022", "module": "es2022", "moduleResolution": "node", "types": ["node"], "esModuleInterop": true, "allowSyntheticDefaultImports": true }, "files": [ "src/main.server.ts" ], "angularCompilerOptions": { "enableIvy": true } } main.server.ts import { bootstrapApplication } from '@angular/platform-browser'; import { AppComponent } from './app/app.component'; import { serverAppConfig } from './app/app.config.server'; const bootstrap = () => bootstrapApplication(AppComponent, serverAppConfig); export default bootstrap; server.ts import 'zone.js/node'; import { APP_BASE_HREF } from '@angular/common'; import { CommonEngine } from '@angular/ssr/node'; import * as express from 'express'; import { existsSync } from 'node:fs'; import { join } from 'nodeath'; import AppServerModule from './src/main.server'; // Define paths const distFolder = join(process.cwd(), 'dist', 'my-app', 'browser'); const serverFolder = join(process.cwd(), 'dist', 'my-app', 'server'); const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? join(distFolder, 'index.original.html') : join(distFolder, 'index.html'); // Initialize CommonEngine for SSR const commonEngine = new CommonEngine(); export function app(): express.Express { const server = express(); server.set('view engine', 'html'); server.set('views', distFolder); // Static Files Serving server.get('*.*', express.static(distFolder, { maxAge: '1y' })); // Angular SSR Rendering server.get('*', (req, res, next) => { const { protocol, originalUrl, baseUrl, headers } = req; commonEngine .render({ bootstrap: AppServerModule, documentFilePath: indexHtml, url: `${protocol}://${headers.host}${originalUrl}`, publicPath: distFolder, providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }], }) .then((html) => res.send(html)) .catch((err) => { console.error('SSR Error:', err); next(err); }); }); return server; } // Start the Server function run(): void { const port = process.env['PORT'] || 44492; const server = app(); server.listen(port, () => { console.log(`✅ Node Express server listening on http://localhost:${port}`); }); } // Ensure Server Only Runs in Standalone Mode declare const __non_webpack_require__: NodeRequire; const mainModule = __non_webpack_require__.main; const moduleFilename = mainModule && mainModule.filename || ''; console.log('✅ Module Filename:', moduleFilename); console.log('✅ Current Filename:', __filename); if (moduleFilename === __filename || moduleFilename.includes('iisnode')) { console.log('✅ Running the SSR server...'); run(); } export default AppServerModule; Program.cs snippet (this was working with CSR) app.UseStaticFiles(new StaticFileOptions { OnPrepareResponse = ctx => { ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=31536000"); } }); app.UseRouting(); app.UseAuthorization(); app.MapControllerRoute( name: "default", pattern: "{controller}/{action=Index}/{id?}"); app.MapFallbackToFile("index.html"); csproj snippet <PropertyGroup> <TargetFramework>net6.0</TargetFramework> <Nullable>enable</Nullable> <IsPackable>false</IsPackable> <SpaRoot>ClientApp\</SpaRoot> <SpaProxyServerUrl>https://localhost:44492</SpaProxyServerUrl> <SpaProxyLaunchCommand>npm run dev:ssr</SpaProxyLaunchCommand> <ImplicitUsings>enable</ImplicitUsings> </PropertyGroup> ... <!-- Copy Browser and Server Builds to wwwroot --> <Target Name="CopySpaFiles" AfterTargets="PublishRunWebpack"> <ItemGroup> <DistBrowserFiles Include="$(SpaRoot)dist\my-app\browser\**" /> <DistServerFiles Include="$(SpaRoot)dist\my-app\server\**" /> </ItemGroup> <Message Importance="high" Text="Copying Angular SSR files to wwwroot..." /> <Copy SourceFiles="@(DistBrowserFiles)" DestinationFolder="wwwroot\%(RecursiveDir)" /> <Copy SourceFiles="@(DistServerFiles)" DestinationFolder="wwwroot\%(RecursiveDir)" /> </Target> Continue reading...