我有一个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。添加了codelanguage


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/

10-09 02:22