ASP.NET MVC - 请求周期中可以检测到静态资源请求的最早点是啥?

Posted

技术标签:

【中文标题】ASP.NET MVC - 请求周期中可以检测到静态资源请求的最早点是啥?【英文标题】:ASP.NET MVC - what is the earliest point in the request cycle where you can detect a static resource request?ASP.NET MVC - 请求周期中可以检测到静态资源请求的最早点是什么? 【发布时间】:2011-07-26 00:11:10 【问题描述】:

为了给这个问题提供一些背景信息,我编写了一个在 Application_BeginRequest 上调用的分析器,但它记录了所有内容(即 javascript、图像等)。虽然可以将过滤添加到分析器客户端作为最后的手段,但我宁愿只在可以确定请求需要路由时才激活分析器。理想情况下,它会在 Application_BeginRequest 中,但我认为如果不对传入的路由请求进行冗余处理,这是不可能的......

简而言之,我可以确定请求是否针对静态资源的请求生命周期中最早的时间点是什么时候,您将如何处理?

是否有可能从 System.Web.Routing.RouteTable 派生或挂接到 System.Web.Routing.RouteTable 并从那里调用我的分析器代码?

【问题讨论】:

【参考方案1】:

有多种选择。 首先 - 使用 Request.PhysicalPath 确定静态文件 - 检查: Check for a static file during Application_BeginRequest?

另一种方法是将其作为处理程序并使用路径来记录要包含的文件类型 (*.aspx),例如在 web.config 中。然后你可以很早就可以访问事件(参见 asp.net 管道)

或者只使用 httpmodule - 检查所有内容并仅分析您提到的非物理项目。

或者 - 使用您当前的方法和第一个链接来简单地检查 Request.PhysicalPath 并希望这对您有用:)

【讨论】:

Request.PhysicalPath 方法的问题在于,如果请求可以直接映射到文件名,则它假定请求是静态的,否则就不是静态请求。例如,我不希望将错误命名的链接或对已删除图像文件的引用仅仅因为磁盘上不存在该文件而被解释为非静态链接。 那么您的代码可能需要检查响应代码以确定这种情况(尽管同样可能适用于丢失的动态文件),因为根据定义,上述物理文件是静态的,您正在寻找静态文件类型。要真正检测到您需要进行文件类型假设或查询 iis 或所有映射的应用程序配置。从技术上讲,我可以让 .js 成为一个动态文件,只需将其映射到 aspnet_isapi 或其他 httphandler,那么您想在哪里画线?【参考方案2】:

我宁愿使用 MVC 过滤器 进行分析,因为 MVC 过滤器允许添加预处理和后处理行为,并且 filterContext 参数应该为您提供足够的信息。

例如,我会为分析创建 ProfilerAttribute

public class ProfilerAttribute : FilterAttribute, IActionFilter, IResultFilter, IExceptionFilter 
    public void OnActionExecuting(ActionExecutingContext filterContext) 
        Debug.WriteLine("Before Action is executing");
    

    public void OnActionExecuted(ActionExecutedContext filterContext) 
        Debug.WriteLine("After Action is executed");
    

    public void OnResultExecuted(ResultExecutedContext filterContext) 
        Debug.WriteLine("After Action Result is executed");            
    

    public void OnResultExecuting(ResultExecutingContext filterContext) 
        Debug.WriteLine("Before Action Result is executing");
    

    public void OnException(ExceptionContext filterContext) 
        Debug.WriteLine("oops! exception");
    

并在Global.ascx中注册为GlobalFilter....

public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
    filters.Add(new HandleErrorAttribute());
    filters.Add(new ProfilerAttribute());

希望对您有所帮助。谢谢。

update:忘了说MVC过滤器只在路由匹配之后执行。因此,您不需要过滤掉静态资源,因为它已经由 MVC 完成。

【讨论】:

我最初使用的是派生控制器类的 ActionExecuting 和 actionExecuted 调用,但问题是它错过了我希望能够分析的视图渲染、路由等内容。 通过实现 IResultFilter,如果您的操作结果是 ViewResult,您可以像查看渲染一样进行分析。所以,你会知道控制器动作是慢还是执行结果慢。由于路由是 Asp.net 的一部分,因此您不能对它做太多的性能改进。要分析 ASP.NET 运行时,您可以使用 ASP.NET 的性能计数器。 goo.gl/uRB8f :) 这篇 MSDN 杂志文章也可能对您有用.. msdn.microsoft.com/en-us/magazine/hh288078.aspx【参考方案3】:

我尝试从不同的角度来处理它,并且对结果更满意。基本上 - 当您根本无法“路由”静态资源请求时,为什么还要检测它们?在 global.asax 中:

private readonly string[] STATIC_CONTENT_PATHS = new string[]  "css", "js", "img" ; 

public static void RegisterRoutes(RouteCollection routes)
    
    foreach (string path in STATIC_CONTENT_PATHS)  routes.IgnoreRoute(path + @"/*foo"); 

    // other MapRoute calls here

现在我不再需要检查静态请求,但如果我出于某种原因确实想要检查,我仍然可以执行以下操作:

protected void Application_BeginRequest()
            
    if (IsStaticRequest())
    
         // do something here
    


private bool IsStaticRequest()

   var result = Request.Url.AbsolutePath.Split('/');
   if (result.Length < 2) return false;
   return STATIC_CONTENT_PATHS.Contains(result[1]);

因为我绝对知道我将提供静态内容的唯一路径是什么,所以这似乎是一个相当强大的解决方案。我仍然对其他想法持开放态度,但我认为这很适合我的需求。

【讨论】:

以上是关于ASP.NET MVC - 请求周期中可以检测到静态资源请求的最早点是啥?的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET MVC5请求管道和生命周期

Asp.net MVC 之请求生命周期

ASP.NET MVC 生命周期

asp.net mvc 生命周期

asp.net MVC 应用程序的生命周期

ASP.NET MVC5 的请求管道和运行生命周期