为什么有关使用尝试错误处理的模糊控制器的异常会使管道混乱?

时间:2015-02-08 10:40:22

标签: asp.net asp.net-mvc iis asp.net-mvc-5 iis-8

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

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

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

要重现:

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

    1. 添加下面提供的HttpModule
    2. 运行该应用程序,这将导致DirectoryListingModule中出现403.14 IIS错误页面。

      1. 删除或重命名新区域中的模糊控制器,但在默认HomeController的索引操作中创建运行时错误(例如DivideByZero)。
      2. 运行应用程序,这将导致200响应“Hello world”,如预期的那样。

        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()
            {
            }
        }
        

        这里发生了什么?当我尝试清除错误并在我们获得有关模糊控制器的异常时更改响应时,为什么会中断?

1 个答案:

答案 0 :(得分:1)

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

  • 如果控制器不明确,路由系统会找到与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)
    

    由于路由模块无法获得处理程序,IIS将尝试使用其他模块处理它。这意味着它将尝试使用IIS上默认启用的DirectoryListingModuleStaticFileModule来提供请求。

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

    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)
    

    因此,在这种情况下,如果抛出异常,系统将不会尝试使用其他模块(例如DirectoryListingModuleStaticFileModule

  • 来提供请求

关于错误处理程序,在模糊控制器的场景中,您需要一种方法来阻止系统找到另一个将处理请求的IHttpHandler(因为尝试获取MvcHandler时出现错误)。 人们还可以争辩说,这样的错误(一个模糊的控制器名称)是一个严重的错误,应该在开发时捕获,永远不应该生产。

在任何情况下,都有一些替代方法,例如转移到静态html文件server.Transfer("Error500.html");,或者在错误处理程序((HttpApplication)sender).CompleteRequest();结束时完成请求等蛮力文件。

因此,例如,当前IHttpHandler为null时,一个选项可能会转移到静态500错误文件,否则保留当前处理程序代码:

private void HandleApplicationError(object sender, EventArgs e)
{
    var application = sender as HttpApplication;        
    var server = application.Server;

    if (application.Context.CurrentHandler == null)
    {
        server.Transfer("Error500.html");
    }
    else
    {
        var response = HttpContext.Current.Response;
        server.ClearError();
        response.Clear();
        response.Write("Hello world");
    }
}