I have the following situation:
/api/*
/health
/svc/*
/app
OR /
(if you go to example.com
it will serve files from /app/
folder. Now, if someone requests an entity which does not exist, an exception is thrown. This is handled by using the following in Startup.cs
app.UseExceptionHandler("/error");
The ErrorController handles these exceptions and return's stuff like NotFound()
, BadRequest()
, etc. In the end, they are all JSON responses.
Now, if you were to go to the /hshfdhfgh
url, this now results in an empty 404 page because nothing matches. But what I would like to do is to be able to add some custom HTML views for error pages. Perhaps with Razor Pages or something.
I have looked this up and you need it is advised to use the UseExceptionHandler("/error")
method so you can return some views. But this would conflict with my JSON responses!
The only thing I can come up with is something like:
if request does not start with /health, /svc/, /, /app or /api/
app.UseExceptionHandler("/error/404");
else
app.UseExceptionHandler("/error");
But this feels very hacky. Is there any other way?
And, what would be the best/easiest way to add razor support to my project? currently it has none.
You can use this as a start (it's netcore 3.1, but I don't think we had to make significant changes when migrating from 2). It feels hacky and it's pain to get the handler itself right, and to put it at the exactly right place in Startup (especially if you combine it with things like dealing properly with Unauthorized responses, razor views and static files for those razor views). But I didn't find a better way.
public static readonly PathString ApiPath = new PathString("/api");
public static readonly PathString StaticFilePath = new PathString("/site");
static bool IsApiRequestPredicate(HttpContext context) => context.Request.Path.StartsWithSegments(ApiPath, StringComparison.InvariantCulture);
static bool IsStaticFilePredicate(HttpContext context) => context.Request.Path.StartsWithSegments(StaticFilePath, StringComparison.InvariantCulture);
...
app.UseWhen(x => !IsApiRequestPredicate(x) && !IsStaticFilePredicate(x), builder =>
{
builder.UseStatusCodePagesWithReExecute("/Error/StatusCodeViewReexecuteHandler/{0}");
app.UseDeveloperExceptionPage();
});
app.UseWhen(x => IsApiRequestPredicate(x), builder =>
{
builder.UseExceptionHandler("/Error/ExceptionApiReexecuteHandler");
builder.UseStatusCodePagesWithReExecute("/Error/StatusCodeApiReexecuteHandler/{0}");
});
You could also use only one handler and decide based on OriginalPath in ErrorController action:
var errorFeature = HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
var exceptionFeature = HttpContext.Features.Get<IExceptionHandlerFeature>();
if (errorFeature.OriginalPath.StartsWith("/api", StringComparison.InvariantCulture))
{
return BadRequest(new { error = "entity not found" });
} else {
return View("NotFound");
}
// exceptionFeature gives you access to the exception thrown
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.