C# 自定义404页面,带JSON,不带重定向
我正在开发一个API,到目前为止,除了404页面(默认的ASP.NET404页面)之外,所有页面都返回JSON。我想更改它,以便它在404页面上也返回JSON。大概是这样的:C# 自定义404页面,带JSON,不带重定向,c#,json,asp.net-mvc,api,http-status-code-404,C#,Json,Asp.net Mvc,Api,Http Status Code 404,我正在开发一个API,到目前为止,除了404页面(默认的ASP.NET404页面)之外,所有页面都返回JSON。我想更改它,以便它在404页面上也返回JSON。大概是这样的: {"Error":{"Code":1234,"Status":"Invalid Endpoint"}} 如果在Global.asax.cs文件中捕获404个错误并重定向到现有路由,则可以获得类似的效果: // file: Global.asax.cs protected void Application_Error(ob
{"Error":{"Code":1234,"Status":"Invalid Endpoint"}}
如果在Global.asax.cs文件中捕获404个错误并重定向到现有路由,则可以获得类似的效果:
// file: Global.asax.cs
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
if (ex is HttpException && ((HttpException)ex).GetHttpCode() == 404)
{
Response.Redirect("/CatchAll");
}
}
// file: HomeController.cs
[Route("CatchAll")]
public ActionResult UnknownAPIURL()
{
return Content("{\"Error\":{\"Code\":1234,\"Status\":\"Invalid Endpoint\"}}", "application/json");
}
但这会将302HTTP代码返回到新URL,这不是我想要的我想返回一个404 HTTP代码,代码体中包含JSON。我怎样才能做到这一点?
我尝试过的事情,但没有成功…
#1-覆盖默认错误页
我想也许我可以覆盖404处理程序中的默认错误页面。我这样试过:
// file: Global.asax.cs
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
if (ex is HttpException && ((HttpException)ex).GetHttpCode() == 404)
{
Response.Clear();
Response.StatusCode = 404;
Response.TrySkipIisCustomErrors = true;
Response.AddHeader("content-type", "application/json");
Response.Write("{\"Error\":{\"Code\":1234,\"Status\":\"Invalid Endpoint\"}}");
}
}
但它只是继续提供默认的ASP错误页面。顺便说一下,我根本没有修改我的web.config
文件
#2-使用“一网打尽”的路线
我尝试在routes表的末尾添加一个“catch all”路由。我的整个路线配置现在看起来是这样的:
// file: RouteConfig.cs
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "NotFound",
url: "{*data}",
defaults: new { controller = "Home", action = "CatchAll", data = UrlParameter.Optional }
);
}
但这也不行。如果我在Application\u Error()
中放置一个断点,我可以看到它仍然以404错误代码结束。我不确定这是怎么可能的,因为“一网打尽”的路线应该是匹配的?但无论如何,它从来没有达到一网打尽的路线
#3-在运行时添加路由
我在另一个SO问题上看到了从错误处理程序中调用新路由的可能性。所以我试着:
// file: Global.asax.cs
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
if (ex is HttpException && ((HttpException)ex).GetHttpCode() == 404)
{
RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Home");
routeData.Values.Add("action", "CatchAll");
Server.ClearError();
Response.Clear();
IController homeController = new HomeController();
homeController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
}
但是,它会产生以下错误:
System.Web.Mvc.dll中发生“System.Web.HttpException”类型的异常,但未在用户代码中处理
其他信息:在controllerMyproject.Controllers.HomeController
上找不到公共操作方法“CatchAll”
控制器肯定有这种方法。我正在使用POST调用API,但是我已经尝试通过在方法之前添加
[HttpPost]
来专门为POST创建控制器,我仍然得到相同的错误。我们在路由表的末尾有一个类似于
config.Routes.MapHttpRoute(
name: "NotImplemented",
routeTemplate: "{*data}",
defaults: new { controller = "Error", action = "notimplemented", data = UrlParameter.Optional });
我们在其中生成自定义响应。您可以在路由表中执行类似的操作。我终于找到了一个有效的解决方案。从上面看基本上是#1,增加了一行:
// file: Global.asax.cs
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
if (ex is HttpException && ((HttpException)ex).GetHttpCode() == 404)
{
Server.ClearError(); // important!!!
Response.Clear();
Response.StatusCode = 404;
Response.TrySkipIisCustomErrors = true;
Response.AddHeader("content-type", "application/json");
Response.Write("{\"Error\":{\"Code\":1234,\"Status\":\"Invalid Endpoint\"}}");
}
}
Server.ClearError()代码>命令似乎非常重要。如果没有它,将返回常规ASP错误页,并且没有任何响应。
方法对返回的数据有任何影响。我尝试了这个方法,但这个新路由从未被命中。相反,Application\u Error()
函数拦截调用。我将把这些信息添加到问题中。