With SpaPrerenderingExtensions
available in ASP.Net core 2.0 JavaScriptServices
, it seems that we can return the HTTP Status Code from the Angular
I am posting this as an answer because I can format things better than in a comment, however this is all untested and based of looking at my outdated solution, your code snippets above, and the Angular6 docs (I don't have the latest VS templates so I can't test at the moment).
The options
parameter object that is given to both renderModule() and renderModuleFactory() has an extraProviders
array that, I believe, will let us add additional providers to the AppServerModule
module.
Here is my idea:
HttpStatusCodeService
from my answer here: Return 404 status code in aspnet core SPA Angular applicationproviders
array in the AppBrowserModule
module (only the browser module, not the server module).
HttpStatusCodeService
in main.server.ts
file and add that instance as a provider in the extraProviders
array.
Here is my untested attempt to modify your main.server.ts
file snippet to work.
import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import { renderModule, renderModuleFactory } from '@angular/platform-server';
import { APP_BASE_HREF } from '@angular/common';
import { enableProdMode } from '@angular/core';
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
import { createServerRenderer } from 'aspnet-prerendering';
export { AppServerModule } from './app/app.module.server';
//ADD THIS LINE
import { HttpStatusCodeService } from './path/to/services/http-status-code.service';
enableProdMode();
export default createServerRenderer(params => {
const { AppServerModule, AppServerModuleNgFactory, LAZY_MODULE_MAP } = (module as any).exports;
//ADD THIS LINE - We manually instantiate the service so we have a reference to it.
let statusCodeService = new HttpStatusCodeService();
const options = {
document: params.data.originalHtml,
url: params.url,
extraProviders: [
provideModuleMap(LAZY_MODULE_MAP),
{ provide: APP_BASE_HREF, useValue: params.baseUrl },
{ provide: 'BASE_URL', useValue: params.origin + params.baseUrl },
//ADD THIS LINE - We add a provider for the service that uses our instance.
{ provide: HttpStatusCodeService, useValue: statusCodeService },
]
};
const renderPromise = AppServerModuleNgFactory
? /* AoT */ renderModuleFactory(AppServerModuleNgFactory, options)
: /* dev */ renderModule(AppServerModule, options);
return renderPromise.then((html) => {
//ADD THIS LINE - get the status code from the service.
let statusCode: number = statusCodeService.getStatusCode();
return {
html: statusCode == 404 ? 'Page not found!' : html, StatusCode: statusCode
}
});
});
In my original solution, I rendered my 404 Not Found page using an Angular component, so I wouldn't override the returned HTML (html: html, statusCode: statusCode
).
And for the sake of completeness, here is the HttpStatusCodeService
from the answer linked to above:
import { Injectable } from '@angular/core';
@Injectable()
export class HttpStatusCodeService {
private statusCode: number;
constructor(){
this.statusCode = 200;
}
public setStatusCode(statusCode: number) {
this.statusCode = statusCode;
}
public getStatusCode(): number {
return this.statusCode;
}
}
Let me know if this works. If it doesn't, I can try to get a test environment set up to poke at this some more, but no promises.