我有一个MVC 5 Web API,如果发生意外异常或找不到控制器或动作,它会返回自定义响应。本质上,我完全按照此处显示的方式进行操作:http://weblogs.asp.net/imranbaloch/handling-http-404-error-in-asp-net-web-api一切都像魅力一样。
问题是:我想将错误代码从SelectController()
和SelectAction()
提交给我的ErrorController
。这样,我就不会有重复的代码,所有逻辑都将在控制器中。
不幸的是,我找不到将错误代码提交到我的控制器的任何可能方法。所有示例都重定向到特定的错误操作(例如ErrorController.NotFound404
),我想重定向到ErrorController.Main
并在那里做所有的魔术。
自定义ApiControllerActionSelector
的另一个问题是Request
属性在null
中是ErrorController
。自定义DefaultHttpControllerSelector
不存在此问题。
有任何想法吗?
最好的祝福,
卡斯滕
最佳答案
幸运的是,我能够自己找到解决方案。让我向您展示如何启动和运行它。
自定义控制器和操作选择器正在转发请求的语言和当前的HTTP响应代码:
public class CustomDefaultHttpControllerSelector: DefaultHttpControllerSelector
{
public CustomDefaultHttpControllerSelector(HttpConfiguration configuration) : base(configuration)
{
}
public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
HttpControllerDescriptor descriptor = null;
try
{
descriptor = base.SelectController(request);
}
catch (HttpResponseException e)
{
var routeValues = request.GetRouteData().Values;
routeValues.Clear();
routeValues["controller"] = "Error";
routeValues["action"] = "Main";
routeValues["code"] = e.Response.StatusCode;
routeValues["language"] = request.Headers?.AcceptLanguage?.FirstOrDefault()?.Value ?? "en";
descriptor = base.SelectController(request);
}
return descriptor;
}
}
public class CustomControllerActionSelector: ApiControllerActionSelector
{
public CustomControllerActionSelector()
{
}
public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
{
HttpActionDescriptor descriptor = null;
try
{
descriptor = base.SelectAction(controllerContext);
}
catch (HttpResponseException e)
{
var routeData = controllerContext.RouteData;
routeData.Values.Clear();
routeData.Values["action"] = "Main";
routeData.Values["code"] = e.Response.StatusCode;
routeData.Values["language"] = controllerContext.Request?.Headers?.AcceptLanguage?.FirstOrDefault()?.Value ?? "en";
IHttpController httpController = new ErrorController();
controllerContext.Controller = httpController;
controllerContext.ControllerDescriptor = new HttpControllerDescriptor(controllerContext.Configuration, "Error", httpController.GetType());
descriptor = base.SelectAction(controllerContext);
}
return descriptor;
}
}
两个重要的变化:
1.1。路由值列表需要清除。否则,它将尝试在
ErrorController
中找到一个映射到此值列表的操作。1.2。添加了
code
和language
。ErrorController
本身:[RoutePrefix("error")]
public class ErrorController: BaseController
{
[HttpGet, HttpPost, HttpPut, HttpDelete, HttpHead, HttpOptions, AcceptVerbs("PATCH")]
[Route("{code}/{language}")]
public HttpResponseMessage Main(string code, string language)
{
HttpStatusCode parsedCode;
var responseMessage = new HttpResponseMessage();
if (!Enum.TryParse(code, true, out parsedCode))
{
parsedCode = HttpStatusCode.InternalServerError;
}
responseMessage.StatusCode = parsedCode;
...
}
}
我已经删除了路由映射
routes.MapHttpRoute(...)
。无论我在浏览器中输入了什么,它都永远不会调用Handle404
。尚未涵盖HTTP状态400(错误请求)。通过使用http://www.asp.net/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web-api中所述的
ValidationModelAttribute
(“处理验证错误”一节)可以轻松实现这一点。也许这会帮助某人...
关于c# - 将值从自定义HttpControllerSelector和HttpActionSelector转发到其描述符,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39326583/