I have an api application with angular in the client side and ASP.NET Core in the backend served by IIS. I'm also using SAML2 to authenticate. My setup is like this:
Client side, angualr.json file:
Project > MyApp > architect > build > options > index: src/root.html
Program.cs
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseContentRoot(System.IO.Directory.GetCurrentDirectory())
.UseIIS()
.UseStartup<Startup>()
.UseNLog()
.Build();
host.Run();
}
Startup.cs in the configure method
app.UseHttpsRedirection();
app.UseHsts();
app.UsePathBase("/api");
app.UseDefaultFiles();
app.UseStaticFiles(new StaticFileOptions()
{
OnPrepareResponse = context =>
{
context.Context.Response.Headers.Add("Cache-Control", "no-cache, no-store");
context.Context.Response.Headers.Add("Expires", "-1");
}
});
if (!env.IsDevelopment())
{
app.UseSpaStaticFiles();
}
app.UseRouting();
app.UseCors();
app.UseSaml2();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
and the web.config is setup like this:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<customErrors mode="Off" />
</system.web>
<location path="." inheritInChildApplications="false">
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Cache-Control" value="private, no-store, no-cache" />
<add name="X-Content-Type-Options" value="nosniff" />
<add name="X-Frame-Options" value="SAMEORIGIN" />
<add name="X-XSS-Protection" value="1; mode=block" />
</customHeaders>
</httpProtocol>
<handlers>
<remove name="StaticFile" />
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="File" requireAccess="Read" />
</handlers>
<aspNetCore processPath=".\MyServer.exe" arguments="" stdoutLogEnabled="false" hostingModel="InProcess" stdoutLogFile=".\logs\out">
<environmentVariables>
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="production" />
<environmentVariable name="ASPNETCORE_HTTPS_PORT" value="43210" />
<environmentVariable name="COMPLUS_ForceENC" value="1" />
</environmentVariables>
</aspNetCore>
<rewrite>
<outboundRules>
<rule name="Add SameSite" preCondition="No SameSite">
<match serverVariable="RESPONSE_Set_Cookie" pattern=".*" negate="false" />
<action type="Rewrite" value="{R:0}; SameSite=strict" />
<conditions>
</conditions>
</rule>
<preConditions>
<preCondition name="No SameSite">
<add input="{RESPONSE_Set_Cookie}" pattern="." />
<add input="{RESPONSE_Set_Cookie}" pattern="; SameSite=strict" negate="true" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
<httpErrors errorMode="Custom">
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" prefixLanguageFilePath="" path="/GenError404.html" responseMode="ExecuteURL" />
</httpErrors>
</system.webServer>
</location>
</configuration>
and in the configureServices method:
services.AddSaml2();
// In production, the Angular files will be served from this directory
if (!Environment.IsDevelopment())
{
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
}
Current Behavior: When app is served, it shows up like this at the root: https:///root.html# And when serving controller, it gets appended to the end: https:///root.html#/product/35
PROBLEM: I'm trying to setup a 404 custom page in my IIS if a controller that doesn't exist gets called, but the behavior if I try something like this: https:///root.html#/bogus, the url immediately sets back to the previous url, but there is an error in the console of chrome:
ERROR oe: NG04002: 'bogus'
at Wue.noMatchError (https://myserver/main.js:1:385012)
at https://myserver/main.js:1:385814
at https://myserver/main.js:1:347833
at Sn._error (https://myserver/main.js:1:17455)
at Sn.error (https://myserver/main.js:1:12087)
at Sn._error (https://myserver/main.js:1:12327)
at Sn.error (https://myserver/main.js:1:12087)
at Sn._error (https://myserver/main.js:1:12327)
at Sn.error (https://myserver/main.js:1:12087)
at Sn._error (https://myserver/main.js:1:12327)
I looked inside the top and there is a bunch of calls to this method:
error(n) {
this.isStopped ? ve(function gu(t) {
return _u("E", void 0, t)
}(n), this) : (this.isStopped = !0, this._error(n))
}
I couldn't figure out which of my settings is telling main.js to handle the destination error and how to make it instead route back to me, so I can show my custom 404 page?