在路由匹配发生之前拦截所有 WebApi 调用

Posted

技术标签:

【中文标题】在路由匹配发生之前拦截所有 WebApi 调用【英文标题】:Intercept all WebApi calls before the route matching occurs 【发布时间】:2018-07-03 12:11:12 【问题描述】:

我正在寻找一种在匹配路由之前拦截/获取正在发出的请求的方法。例如,我设置了多个控制器和路由,但我想要一些在路由方法被命中之前会被命中的机制。如果这种机制能够获取发送的路由参数,那将是非常可取的。

我一直无法找到与我正在寻找的内容相似的内容(但可能不精通 Web API,我正在使用错误的关键字进行搜索)。

【问题讨论】:

您可以查看 global.asax 中的 Application_BeginRequest。 【参考方案1】:

您需要的是操作过滤器。您可以将动作过滤器作为属性直接应用于控制器,动作过滤器的警告是,此时控制器路由是已知的,但您仍然可以控制(非常类似于 AOP)动作方法是否可以执行:

ASP.NET Web API ActionFilter example

看看如何使用操作过滤器,在这种情况下用于记录:

public class LogActionFilter : ActionFilterAttribute 

    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    
        Log(actionExecutedContext.ActionContext.RequestContext.RouteData);

        base.OnActionExecuted(actionExecutedContext);
    

    private void Log(System.Web.Http.Routing.IHttpRouteData httpRouteData)
    
        var controllerName = "controller name";
        var actionName = "action name";
        var message = String.Format("controller:0, action:1", controllerName, actionName);

    Debug.WriteLine(message, "Action Filter Log");
    

How to log which action method is executed in a controller in webapi

您还可以使用消息处理程序,它们在控制器被解析之前执行:

HTTP Message Handlers in ASP.NET Web API

【讨论】:

I am looking for a way to intercept/grab the request being made before matching to a route -- 动作过滤器在路由匹配后出现,不是吗?也可能是问题不够清楚,无法提供正确的答案 如果这是你想要的,你可以使用消息处理程序,在发现路由之前你需要做什么? 我只是从 OP 中引用问题的一部分,因为我认为您的回答可能错过了它的这方面 :) 也许我在比赛开始前说错了。我的意思是在调用匹配的方法之前。在这种情况下,我能够使用“OnActionExecuting”,以便在调用控制器中的方法之前命中该代码块。这正是我所需要的,并且看起来是对我来说最好的整体解决方案 对于大多数情况,动作过滤器都很好,很高兴我能提供帮助:-)【参考方案2】:

我正在使用上述技术来记录所有请求和响应。 简短地说,最好的方法是使用处理程序。

首先,创建处理程序:

public class CustomHandler : DelegatingHandler

    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    
        //get route values and process them
        var routeValues = (IHttpRouteData[]) HttpContext.Current.Request.RequestContext.RouteData.Values["MS_SubRoutes"];

        //let other handlers process the request
        return await base.SendAsync(request, cancellationToken)
            .ContinueWith(task =>
            
                //once response is ready, do something with it                                        

                return task.Result;
            , cancellationToken);
    

然后,在 WebApiConfig 中注册:

config.MessageHandlers.Add(new CustomHandler());

【讨论】:

如果您使用委托处理程序记录所有请求,您还将记录无效请求,如果您只需要记录您应该使用操作过滤器而不是处理程序。 @Marco 那些也对我感兴趣 :) 它们都允许您记录您的请求,但使用操作过滤器更容易让您只记录有意义的数据:)【参考方案3】:

是否可以创建一个 HttpHandler(或仅在 Global asax Application_BeginRequest 事件中执行)来捕获请求并在处理程序内部根据路由配置解析 URL,类似于 this link。

【讨论】:

您可以通过 Web API 提供的更好的方法来实现这一点。【参考方案4】:

就像 cmets 中提到的 Joel Etherton 一样,我认为您正在寻找的是在 global.asax 中添加以下代码:

protected void Application_EndRequest()

    /*
    if(HttpContext.Current.Response.StatusCode == 404)
        Debug.WriteLine("404 something something")
    if(HttpContext.Current.Response.StatusCode == 500)
        Debug.WriteLine("500 something something")
    if(HttpContext.Current.Response.StatusCode == 200)
        Debug.WriteLine("200 something something")
    */
    Debug.WriteLine($"context.Response.StatusCode - request.Url.PathAndQuery");

我的灵感来自这里:ASP.NET MVC 404 Error Handling

【讨论】:

以上是关于在路由匹配发生之前拦截所有 WebApi 调用的主要内容,如果未能解决你的问题,请参考以下文章

WebApi-路由机制

路由守卫和拦截器

MVC & WebAPI“找到多个类型匹配名为...的控制器”

WebApi 找到了与该请求匹配的多个操作

WebAPI 核心路由问题

使用自定义指令/操作时路由匹配的控制顺序