Asp.net 为什么一个含糊不清的控制器尝试错误处理的例外会扰乱管道?

Asp.net 为什么一个含糊不清的控制器尝试错误处理的例外会扰乱管道?,asp.net,asp.net-mvc,iis,asp.net-mvc-5,iis-8,Asp.net,Asp.net Mvc,Iis,Asp.net Mvc 5,Iis 8,我正在尝试一些错误处理,而这个特定的错误似乎把事情搞砸了 我有一个订阅HttpApplication.Error事件处理程序的HttpModule(见下文),在这里我清除错误并编写一些虚拟响应内容 这对“正常”应用程序错误很好,但是当我得到关于不明确控制器的错误时,它会像往常一样进入处理程序,但是更改的响应被完全忽略,管道中的执行流似乎有一些小故障,对MVC之外的相同资源创建IIS子请求,根据请求的原始路径,导致IIS错误页面,该页面无法列出目录或文件不存在 复制: 创建一个新的模板化MVC项目

我正在尝试一些错误处理,而这个特定的错误似乎把事情搞砸了

我有一个订阅HttpApplication.Error事件处理程序的HttpModule(见下文),在这里我清除错误并编写一些虚拟响应内容

这对“正常”应用程序错误很好,但是当我得到关于不明确控制器的错误时,它会像往常一样进入处理程序,但是更改的响应被完全忽略,管道中的执行流似乎有一些小故障,对MVC之外的相同资源创建IIS子请求,根据请求的原始路径,导致IIS错误页面,该页面无法列出目录或文件不存在

复制:

  • 创建一个新的模板化MVC项目
  • 添加新区域并创建HomeController(这将与默认HomeController冲突)
  • 运行应用程序时,您应该会看到一个关于不明确控制器的ASP.NET错误页面

  • 添加下面提供的HttpModule
  • 运行应用程序,这将导致DirectoryListingModule出现403.14 IIS错误页面

  • 在新区域中删除或重命名不明确的控制器,但在默认HomeController的索引操作中创建运行时错误(例如DivideByZero)
  • 运行该应用程序,这将产生一个200响应,并如预期的那样显示“helloworld”

    public class HttpModule : IHttpModule
    {
        public void Init(HttpApplication context)
        {
            context.Error += HandleApplicationError;
        }
    
        private void HandleApplicationError(object sender, EventArgs e)
        {
            var response = HttpContext.Current.Response;
            var server = ((HttpApplication)sender).Server;
            server.ClearError();
            response.Clear();
            response.Write("Hello world");
        }
    
        public void Dispose()
        {
        }
    }
    

    这里发生了什么?当我试图清除错误并更改响应时,当我们得到关于不明确控制器的异常时,为什么会出现问题?

    该行为取决于引发请求处理管道异常的位置

    • 在控制器不明确的情况下,路由系统会找到与url匹配的路由,并尝试获取将处理请求的IHttpHandler。但是,在尝试获取IHttpHandler时引发异常,请检查此堆栈跟踪:

      at System.Web.Mvc.DefaultControllerFactory.GetControllerTypeWithinNamespaces(RouteBase route, String controllerName, HashSet`1 namespaces)
      at System.Web.Mvc.DefaultControllerFactory.GetControllerType(RequestContext requestContext, String controllerName)
      at System.Web.Mvc.DefaultControllerFactory.System.Web.Mvc.IControllerFactory.GetControllerSessionBehavior(RequestContext requestContext, String controllerName)
      at System.Web.Mvc.MvcRouteHandler.GetSessionStateBehavior(RequestContext requestContext)
      at System.Web.Mvc.MvcRouteHandler.GetHttpHandler(RequestContext requestContext)
      at System.Web.Mvc.MvcRouteHandler.System.Web.Routing.IRouteHandler.GetHttpHandler(RequestContext requestContext)
      at System.Web.Routing.UrlRoutingModule.PostResolveRequestCache(HttpContextBase context)
      at System.Web.Routing.UrlRoutingModule.OnApplicationPostResolveRequestCache(Object s atder, Ev attArgs e)
      at System.Web.HttpApplication.SyncEv attExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
      at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
      
      at WebApplication3.Controllers.HomeController.ThrowError() at g:\Documents\Visual Studio 2012\Projects\WebApplication3\WebApplication3\Controllers\HomeController.cs:line 32
      at lambda_method(Closure , ControllerBase , Object[] )
      at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
      at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
      at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
      at System.Web.Mvc.Async.AsyncControllerActionInvoker.ActionInvocation.InvokeSynchronousActionMethod()
      at System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__36(IAsyncResult asyncResult, ActionInvocation innerInvokeState)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
      at System.Web.Mvc.Async.AsyncResultWrapper.End[TResult](IAsyncResult asyncResult, Object tag)
      at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
      at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3c()
      at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass45.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3e()
      at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass30.<BeginInvokeActionMethodWithFilters>b__2f(IAsyncResult asyncResult)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
      at System.Web.Mvc.Async.AsyncResultWrapper.End[TResult](IAsyncResult asyncResult, Object tag)
      at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult)
      at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass1e.<>c__DisplayClass28.<BeginInvokeAction>b__19()
      at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass1e.<BeginInvokeAction>b__1b(IAsyncResult asyncResult)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
      at System.Web.Mvc.Async.AsyncResultWrapper.End[TResult](IAsyncResult asyncResult, Object tag)
      at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult)
      at System.Web.Mvc.Controller.<BeginExecuteCore>b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
      at System.Web.Mvc.Async.AsyncResultWrapper.End[TResult](IAsyncResult asyncResult, Object tag)
      at System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag)
      at System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult)
      at System.Web.Mvc.Controller.<BeginExecute>b__15(IAsyncResult asyncResult, Controller controller)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
      at System.Web.Mvc.Async.AsyncResultWrapper.End[TResult](IAsyncResult asyncResult, Object tag)
      at System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag)
      at System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult)
      at System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult)
      at System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__4(IAsyncResult asyncResult, ProcessRequestState innerState)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
      at System.Web.Mvc.Async.AsyncResultWrapper.End[TResult](IAsyncResult asyncResult, Object tag)
      at System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag)
      at System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult)
      at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)
      at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
      at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
      
      由于路由模块无法获取处理程序,IIS将尝试使用其他模块处理它。这意味着它将尝试使用IIS上默认启用的
      DirectoryListingModule
      StaticFileModule
      为请求提供服务

    • 当在控制器操作中引发异常时,请求已经分配了一个IHttpHandler,该IHttpHandler正在处理该请求。检查不同的堆栈跟踪:

      at System.Web.Mvc.DefaultControllerFactory.GetControllerTypeWithinNamespaces(RouteBase route, String controllerName, HashSet`1 namespaces)
      at System.Web.Mvc.DefaultControllerFactory.GetControllerType(RequestContext requestContext, String controllerName)
      at System.Web.Mvc.DefaultControllerFactory.System.Web.Mvc.IControllerFactory.GetControllerSessionBehavior(RequestContext requestContext, String controllerName)
      at System.Web.Mvc.MvcRouteHandler.GetSessionStateBehavior(RequestContext requestContext)
      at System.Web.Mvc.MvcRouteHandler.GetHttpHandler(RequestContext requestContext)
      at System.Web.Mvc.MvcRouteHandler.System.Web.Routing.IRouteHandler.GetHttpHandler(RequestContext requestContext)
      at System.Web.Routing.UrlRoutingModule.PostResolveRequestCache(HttpContextBase context)
      at System.Web.Routing.UrlRoutingModule.OnApplicationPostResolveRequestCache(Object s atder, Ev attArgs e)
      at System.Web.HttpApplication.SyncEv attExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
      at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
      
      at WebApplication3.Controllers.HomeController.ThrowError() at g:\Documents\Visual Studio 2012\Projects\WebApplication3\WebApplication3\Controllers\HomeController.cs:line 32
      at lambda_method(Closure , ControllerBase , Object[] )
      at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
      at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
      at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
      at System.Web.Mvc.Async.AsyncControllerActionInvoker.ActionInvocation.InvokeSynchronousActionMethod()
      at System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__36(IAsyncResult asyncResult, ActionInvocation innerInvokeState)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
      at System.Web.Mvc.Async.AsyncResultWrapper.End[TResult](IAsyncResult asyncResult, Object tag)
      at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
      at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3c()
      at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass45.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3e()
      at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass30.<BeginInvokeActionMethodWithFilters>b__2f(IAsyncResult asyncResult)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
      at System.Web.Mvc.Async.AsyncResultWrapper.End[TResult](IAsyncResult asyncResult, Object tag)
      at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult)
      at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass1e.<>c__DisplayClass28.<BeginInvokeAction>b__19()
      at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass1e.<BeginInvokeAction>b__1b(IAsyncResult asyncResult)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
      at System.Web.Mvc.Async.AsyncResultWrapper.End[TResult](IAsyncResult asyncResult, Object tag)
      at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult)
      at System.Web.Mvc.Controller.<BeginExecuteCore>b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
      at System.Web.Mvc.Async.AsyncResultWrapper.End[TResult](IAsyncResult asyncResult, Object tag)
      at System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag)
      at System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult)
      at System.Web.Mvc.Controller.<BeginExecute>b__15(IAsyncResult asyncResult, Controller controller)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
      at System.Web.Mvc.Async.AsyncResultWrapper.End[TResult](IAsyncResult asyncResult, Object tag)
      at System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag)
      at System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult)
      at System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult)
      at System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__4(IAsyncResult asyncResult, ProcessRequestState innerState)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
      at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
      at System.Web.Mvc.Async.AsyncResultWrapper.End[TResult](IAsyncResult asyncResult, Object tag)
      at System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag)
      at System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult)
      at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)
      at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
      at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
      

      谢谢,看起来不错,但有一件事我仍然不明白,那就是如果我们禁用自定义错误处理,“UrlRoutingModule-4.0”会导致默认错误页面,并且它不会尝试DirectoryListingModule或StaticFileModule。如果您描述的行为是由IIS查找处理程序的失败尝试引起的,为什么只有在我尝试清除响应时才会触发此操作?我清除响应是否会导致IIS对刚才发生的事情产生误解?可能是因为当我不清除错误时,IIS会在尝试获取处理程序失败后将错误注册到管道中,并使用此操作在另一个处理程序中生成错误页,独立于获取处理程序的原始失败尝试。因此,当我清除错误时,IIS不会触发错误页面模块并继续搜索…而不调用
      服务器。ClearError
      错误将不断扩展,直到asp最终处理它,生成死亡的黄屏。因此,如果您删除错误处理代码,或注释调用
      ClearError
      的行,您将看到YSODDo,您是否确切地知道此错误是如何升级的?是否都在UrlRoutingModule中处理?我在看跟踪文件,但没什么收获。希望有一种更明确的方式来遵循IIS的流程。我恐怕不知道导致YSOD的asp net内部异常处理过程,但我猜它将是默认asp net请求管道的一部分。如果将
      Application\u Error
      Application\u EndRequest
      方法添加到global.asax,您将看到在错误发生后触发结束请求,并且清除响应并用YSOD替换,因此可能有一个全局模块订阅了OnError事件。(我不熟悉此代码,因此可能是错的)