【发布时间】:2016-05-04 12:20:44
【问题描述】:
我把 external 放在括号里,虽然它并不完全正确。解释如下:
我有一个 MVC ASP.NET 应用程序(一个解决方案),它由以下项目组成:
- 业务逻辑
- WebApi(纯WebApi2控制器,基于(1)返回json序列化数据)
- 前端(MVC、Razor 视图等)
前端依赖webapi项目,前端的RouteConfig为自己注册路由和为webapi项目:
//register frontend routes, default code
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
//calls webapi project to register its routes:
//var config = GlobalConfiguration.Configuration;
//... call webApi project
config.Routes.MapHttpRoute(
name: "AppDefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "AppCustomApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
在此配置中,我可以只部署和运行前端和访问功能,如下所示:
- http://server/application/someview -- 访问前端
- http://server/application/api/someapimethod -- 访问api (这是我在这里问的问题:ASP.NET MVC, Web API: working in multiple deployments)
现在我在注册 WebApi 项目中发生的异常时遇到了问题。错误和异常处理在 FrontEndProject 中完美运行:
- 如果代码中存在未处理的异常(抛出 new ArgumentException("hello, there"))
- 如果我访问错误地址时出现http错误http://server/application/somefakeaddress
- 如果有问题,比如解析参数http://server/application/someview?parameter=unparseable_parameter
我可以通过各种方式捕获这些异常和错误(目前我使用 HttpModule 的自定义实现)
现在,这里有一个问题。异常和错误处理不适用于对 WebApi 项目的调用。 (http://server/application/api/...)。在浏览器中我收到正确的回复,例如尝试调用不存在的方法会导致: 在调试输出中:
AuditModule: 2016-05-04 14:15:45,201 [56] INFO AuditModule [(null)] - Request::begin
iisexpress.exe Information: 0 : Request, Method=GET, Url=http://localhost:52258/api/controller_name/fake_method, Message='http://localhost:52258/api/controller_name/fake_method'
iisexpress.exe Information: 0 : Message='controller_name', Operation=DefaultHttpControllerSelector.SelectController
iisexpress.exe Information: 0 : Message='Application.Controllers.controller_nameController', Operation=DefaultHttpControllerActivator.Create
iisexpress.exe Information: 0 : Message='Application.Controllers.controller_nameController', Operation=HttpControllerDescriptor.CreateController
iisexpress.exe Information: 0 : Message='Will use same 'JsonMediaTypeFormatter' formatter', Operation=JsonMediaTypeFormatter.GetPerRequestFormatterInstance
iisexpress.exe Information: 0 : Message='Selected formatter='JsonMediaTypeFormatter', content-type='application/json; charset=utf-8'', Operation=DefaultContentNegotiator.Negotiate
iisexpress.exe Warning: 0 : Message='UserMessage='No HTTP resource was found that matches the request URI 'http://localhost:52258/api/controller_name/fake_method'.', MessageDetail='No action was found on the controller 'controller_name' that matches the request.'', Operation=ApiControllerActionSelector.SelectAction, Status=404 (NotFound), Exception=System.Web.Http.HttpResponseException: Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the 'Response' property of this exception for deta
at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext)
at System.Web.Http.Controllers.ApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext)
at System.Web.Http.Tracing.Tracers.HttpActionSelectorTracer.<>c__DisplayClass2.<System.Web.Http.Controllers.IHttpActionSelector.SelectAction>b__0()
at System.Web.Http.Tracing.ITraceWriterExtensions.TraceBeginEnd(ITraceWriter traceWriter, HttpRequestMessage request, String category, TraceLevel level, String operatorName, String operationName, Action`1 beginTrace, Action execute, Action`1 endTrace, Action`1 errorTrace)
iisexpress.exe Warning: 0 : Message='UserMessage='No HTTP resource was found that matches the request URI 'http://localhost:52258/api/controller_name/fake_method'.', MessageDetail='No action was found on the controller 'controller_name' that matches the request.'', Operation=controller_nameController.ExecuteAsync, Status=404 (NotFound), Exception=System.Web.Http.HttpResponseException: Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the 'Response' property of this exception for deta
at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext)
at System.Web.Http.Controllers.ApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext)
at System.Web.Http.Tracing.Tracers.HttpActionSelectorTracer.<>c__DisplayClass2.<System.Web.Http.Controllers.IHttpActionSelector.SelectAction>b__0()
at System.Web.Http.Tracing.ITraceWriterExtensions.TraceBeginEnd(ITraceWriter traceWriter, HttpRequestMessage request, String category, TraceLevel level, String operatorName, String operationName, Action`1 beginTrace, Action execute, Action`1 endTrace, Action`1 errorTrace)
at System.Web.Http.Tracing.Tracers.HttpActionSelectorTracer.System.Web.Http.Controllers.IHttpActionSelector.SelectAction(HttpControllerContext controllerContext)
at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)
at System.Web.Http.Tracing.Tracers.HttpControllerTracer.<ExecuteAsyncCore>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__18`1.MoveNext()
iisexpress.exe Information: 0 : Response, Status=404 (NotFound), Method=GET, Url=http://localhost:52258/api/controller_name/fake_method, Message='Content-type='application/json; charset=utf-8', content-length=unknown'
iisexpress.exe Information: 0 : Operation=JsonMediaTypeFormatter.WriteToStreamAsync
iisexpress.exe Information: 0 : Operation=controller_nameController.Dispose
AuditModule: 2016-05-04 14:15:45,236 [56] INFO AuditModule [(null)] - Request::end
The thread 0x6398 has exited with code 0 (0x0).
在浏览器中(使用正确的 http 响应代码,在本例中为 404):
{
"Message": "No HTTP resource was found that matches the request URI 'http://localhost:52258/api/controller_name/fake_method'.",
"MessageDetail": "No action was found on the controller 'controller_name' that matches the request."
}
我试过了:
- IHttpModule 实现的相同实例未捕获;它捕获 BeginRequest 和 EndRequest,但不捕获异常(既不是 in-code,也不是 http)
- 每当我使用注册过滤器的技术时,异常过滤器和处理程序都不会捕获
- 通过 config.Services.Replace() 替换服务
最初的问题来自于要求对应用程序中发生的所有事情进行良好的审计跟踪——所有成功和失败的请求都发生在前端和 API 中。我正在使用 Log4net 记录这些(和其他)事件。
因此是我的问题 - 任何人都可以建议另一种方法来在此配置中注册 所有 异常(代码中,http)或指出问题可能来自哪里?
谢谢!
更新 1: 我能够通过标准捕获代码内(当我在 WebApi 方法中抛出异常时): GlobalConfiguration.Configuration.Filters.Add(new CustomExceptionFilterAttribute());
更新 2: 如果我执行以下操作:
public class MyExceptionFilter : IExceptionFilter {...}
GlobalConfiguration.Configuration.Filters.Add(new MyExceptionFilter ());
然后不调用 MyExceptionFilter。但是,调用了 ExceptionFilterAttribute 的 impl。
那么我剩下的就是如何捕获 http(WebApi 的错误路径)和框架(不可解析的参数等)错误和异常。
upd3:已解决。这是我的解决方案的步骤。不幸的是,解决方案有点脆弱,需要一定的初始化步骤序列,不太容易出错:
-
在 Application_Start 中,在注册任何路由之前:
GlobalConfiguration.Configuration.Services.Add(typeof(IExceptionLogger), new AuditExceptionLogger());
注册前端路由
- 注册 WebApi 路由
-
注册 404 处理程序并创建错误控制器
RouteTable.Routes.MapHttpRoute( 名称:“Error404”, routeTemplate: "{*url}", 默认值:新{控制器=“错误”,动作=“Handle404”} );
-
实现 DefaultHttpControllerSelector 和 ApiControllerActionSelector,在那里捕获异常并替换为
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector), new HttpNotFoundAwareDefaultHttpControllerSelector(GlobalConfiguration.Configuration)); GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpActionSelector), new HttpNotFoundAwareControllerActionSelector());
而且我还没有设计 CustomError 处理——我想向无效的前端请求显示正确的错误页面
【问题讨论】:
-
是的,我做到了。事实证明(参见我的上一个更新)init 的顺序非常重要。最后,我确实正确处理了所有异常和错误,它不像我希望的那样容易出错。
-
啊,我明白了。我建议将您的解决方案发布为其他人的问题的答案(并将其标记为答案)。
-
我一定会的。我只是还不确定这是否真的是最好的方法。
标签: c# asp.net asp.net-mvc asp.net-web-api