当 HttpModule 中抛出异常时 ASP.NET MVC 中的自定义错误消息

发布于 2024-11-08 22:27:00 字数 1202 浏览 0 评论 0原文

我正在使用 ASP.NET MVC。我在 BaseController 中的 OnException 上捕获任何未处理的异常,以正确显示友好的消息。

但是我在同一解决方案中有一个 Http 模块项目。如果用户发出错误的请求,模块可能会抛出InvalidOperationException。我使用的是 IIS7 集成模式,所有配置均已正确。我是 IIS 生命周期和 Http 模块异常的新手。

谷歌搜索只找到了使用 HttpMethod 进行异常处理的方法,这与本例不同。

问题是如果模块中抛出异常,MVC 是否会执行?如果确实如此,为什么它不去OnException?以及如何在MVC中像Action方法一样获取异常?

编辑:根据@nickvane关于应用程序生命周期的回答,我尝试更好地解释这种情况。我认为即使是我创建的任何 HttpModule 也可能会抛出任何异常。我希望这个异常由 UrlRoutingModule 中的 MVC 处理。我在想一个:

  • HttpModule Unhandled 异常的顺序
  • 确实会停止模块并且下一个模块将永远不会运行?
  • 如果在 UrlRoutingModule 之前或之后执行的另一个 HttpModule 中抛出异常,如何处理 MVC Web 应用程序 (UrlRoutingModule) 中的异常。
  • 我可以使用 context.AllErrorscontext.Error 获取另一个模块中抛出的异常吗?但我无法得到错误。

我在这个星球上发现的唯一方法是从抛出异常更改为 Server.Transfer() 但其他不属于我的模块怎么样,它仍然抛出异常,我想捕获它。

想一想:我创建了 MVC Restful API,它必须返回 JSON。我可以使用 OnException 正确处理 MVC 应用程序中的任何异常,以便任何未处理的异常都会返回类似 {"Error": "An error message here."} 的内容。现在我的 HttpModule 可能会抛出错误。该模块不关心 API 和 JSON,它只是抛出异常。然后我尝试在 MVC 中捕获此异常,以 JSON 格式返回。

I am using ASP.NET MVC. I trap any unhandled exception on OnException in BaseController to properly show the nice message.

However I have an Http Module project in the same solution. The module may throw an InvalidOperationException if user make a wrong request. I am using IIS7 Integrated mode and all has been configured properly. I am new to IIS life time and Http module exception.

Googling only found the way to do exception handling using HttpMethod which is different from this case.

The question is if the exception has been thrown in the module does the MVC will execute or not? If it does why it not going to OnException? and how to get the exception in the MVC like at Action method?

Edit: Based on answer @nickvane about application lifecycle, I try to explain the situation better. What I think is any HttpModule even created by me may throwing any exception. I want this exception being handled by my MVC which is in UrlRoutingModule. I am thinking of a:

  • The order of HttpModule
  • Unhandled exception does stop the module and next module will never run?
  • How to handle an exception in MVC web app (UrlRoutingModule) if just thrown in another HttpModule either executed before or after UrlRoutingModule.
  • Can I get the exception thrown in another module by using context.AllErrors or context.Error? But I unable to get the errror.

The only way I found on the planet is change from the throwing an exception to Server.Transfer() but how about the other modules that is not mine, it still throwing an exception and I want to catch it.

Think of this: I create MVC Restful API which MUST return a JSON. I can properly handled any exception in MVC app using OnException so that any unhandled exception will return somethig like {"Error": "An error message here."}. Now I have HttpModule that posibbly throw an error. The module does not concern about the API and JSON, it simply throw an exception. Then I try to catch this exception in MVC to return in the JSON formatted.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

等往事风中吹 2024-11-15 22:27:01

控制器或 httpmodule 的生命周期非常不同。
此链接显示了 ASP.NET 应用程序的生命周期:

http://msdn.microsoft .com/en-us/library/bb470252.aspx

虽然它不是专门用于 ASP.NET MVC,但 MVC 框架插入此生命周期并遵循此管道:

http://ajaxus.net/wp-content/uploads/2010/01/asp_net_mvc_poster.pdf

来自< a href="http://www.asp.net/mvc/tutorials/understanding-the-asp-net-mvc-execution-process-vb" rel="nofollow">http://www.asp.net/ mvc/教程/理解-asp-net-mvc-execution-process-vb

对基于 ASP.NET MVC 的 Web 的请求
应用程序首先通过
UrlRoutingModule 对象,它是一个
HTTP 模块。该模块解析
请求并执行路由选择。
UrlRoutingModule 对象选择
第一个匹配的路由对象
当前请求。 (路线对象
是一个实现 RouteBase 的类,
并且通常是一个实例
路由类别。)如果没有路由匹配,则
UrlRoutingModule 对象不执行任何操作
并让请求回退到
常规 ASP.NET 或 IIS 请求
加工。

从选定的路线对象中,
UrlRoutingModule 对象获取
IRouteHandler 对象是
与 Route 对象关联。
通常,在 MVC 应用程序中,这
将是一个实例
MvcRouteHandler。 IRouteHandler
实例创建一个 IHttpHandler
对象并向其传递 IHttpContext
目的。默认情况下,IHttpHandler
MVC 的实例是 MvcHandler
目的。然后是 MvcHandler 对象
选择将要执行的控制器
最终处理请求。

HttpModule 插入应用程序生命周期,并且可以在实例化控制器之前或释放控制器之后执行代码,具体取决于它处理应用程序生命周期中的哪些事件。所以它不能使用控制器的异常处理。

如果你想正确处理 httpmodule 中的异常,我认为你有 2 个选择:

  1. 当你捕获异常时,你可以改变请求的响应。您可以插入错误 div 或用错误消息替换整个响应或仅记录异常。在这种情况下,请求将遵循管道的其余部分。
  2. 或者您可以抛出异常并在 global.asax Application_Error 方法中处理它。在这种情况下,控制器将不会被执行。

如果 HttpModule 抛出有效的异常,那么我会选择选项 2。您可以抛出自己的自定义异常并在 global.asax 中以不同的方式处理它,甚至返回 HTTP 响应(400 Bad Request)。

更新

如果 HttpModule 中抛出异常,它将被 Application_Error 方法捕获。我尝试了以下有效的代码片段,尽管感觉不正确:

protected void Application_Error()
    {
        var ex = Server.GetLastError(); // get the last exception that was made
        if (ex == null) return; // if there is no exception, just continue
        Response.ClearContent();
        Response.Write("{'error':'" + ex.Message + "'}");
        Response.ContentType = "application/json";
        Response.Flush(); // flush the content to the client
        Response.Close(); // and close the connection so that no other content can be written to the response
        Server.ClearError(); // clear the error so that asp.net does not use the custom error page. If we don't close the response and clear the error, the request will still be handled in the rest of the pipeline.
    }

The lifetime of a controller or a httpmodule are very different.
This link shows the lifecycle of an asp.net application:

http://msdn.microsoft.com/en-us/library/bb470252.aspx

Although it isn't for asp.net mvc specifically, the mvc framework plugs into this lifecycle and follows this pipeline:

http://ajaxus.net/wp-content/uploads/2010/01/asp_net_mvc_poster.pdf

From http://www.asp.net/mvc/tutorials/understanding-the-asp-net-mvc-execution-process-vb

Requests to an ASP.NET MVC-based Web
application first pass through the
UrlRoutingModule object, which is an
HTTP module. This module parses the
request and performs route selection.
The UrlRoutingModule object selects
the first route object that matches
the current request. (A route object
is a class that implements RouteBase,
and is typically an instance of the
Route class.) If no routes match, the
UrlRoutingModule object does nothing
and lets the request fall back to the
regular ASP.NET or IIS request
processing.

From the selected Route object, the
UrlRoutingModule object obtains the
IRouteHandler object that is
associated with the Route object.
Typically, in an MVC application, this
will be an instance of
MvcRouteHandler. The IRouteHandler
instance creates an IHttpHandler
object and passes it the IHttpContext
object. By default, the IHttpHandler
instance for MVC is the MvcHandler
object. The MvcHandler object then
selects the controller that will
ultimately handle the request.

A HttpModule plugs into the application lifecycle and can execute code before a controller has been instantiated or after it has been disposed, depending at which events it handles from the application lifecycle. So it can't use the exception handling of the controller.

If you want to handle the exception in the httpmodule properly I think you have 2 options:

  1. When you catch an exception you can alter the response of the request. You could insert an error div or replace the entire response with an error message or just log the exception. In this scenario the request will follow the rest of the pipeline.
  2. Or you can throw the exception and handle it in the global.asax Application_Error method. In this scenario the controller won't be executed.

If the HttpModule is throwing a valid exception then I would go for option 2. You can throw your own custom exception and handle it differently in the global.asax, even returning a HTTP response (400 Bad Request).

Update

If an exception is thrown in an HttpModule it will be caught by the Application_Error method. I tried following code snippet that works, although it feels not right:

protected void Application_Error()
    {
        var ex = Server.GetLastError(); // get the last exception that was made
        if (ex == null) return; // if there is no exception, just continue
        Response.ClearContent();
        Response.Write("{'error':'" + ex.Message + "'}");
        Response.ContentType = "application/json";
        Response.Flush(); // flush the content to the client
        Response.Close(); // and close the connection so that no other content can be written to the response
        Server.ClearError(); // clear the error so that asp.net does not use the custom error page. If we don't close the response and clear the error, the request will still be handled in the rest of the pipeline.
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文