如何捕获MVC ASP.NET中的异常以调用(外部)WebApi项目

时间:2016-05-04 12:20:44

标签: c# asp.net asp.net-mvc asp.net-web-api

我把外部括在括号中,但并不完全正确。这是解释:

我有一个MVC ASP.NET应用程序(一个解决方案),它包含以下项目:

  1. BusinessLogic
  2. WebApi(纯WebApi2控制器,返回基于(1)的json序列化数据)
  3. 前端(MVC,Razor观点等)
  4. 前端取决于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 }
    );
    

    在此配置中,我可以部署并运行前端和访问功能,如下所示:

    现在我在注册WebApi项目中发生的异常时遇到了问题。错误和异常处理在FrontEndProject中完美运行:

    我可以通过各种方式捕获这些异常和错误(目前我使用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."
    }
    

    我试过了:

    1. IHttpModule实现的相同实例无法捕获;它捕获BeginRequest和EndRequest,但不是异常(既不是in-code,也不是http)
    2. 只要我用来注册过滤器的技术
    3. ,异常过滤器和处理程序就无法捕获
    4. 通过config.Services.Replace()
    5. 替换服务

      最初的问题来自要求对应用程序中发生的所有事情留下精细的审计跟踪 - 在前端和API中发生的所有成功和失败的请求。我正在使用Log4net来记录这些(和其他)事件。

      因此是我的问题 - 任何人都可以提出另一种方法来在此配置中注册所有例外(代码内,http)或指出问题可能来自何处?

      谢谢!

      upd 1: 我可以通过标准捕获in-code(当我在WebApi方法中抛出异常时):     GlobalConfiguration.Configuration.Filters.Add(new CustomExceptionFilterAttribute());

      upd 2: 如果我执行以下操作:

      public class MyExceptionFilter : IExceptionFilter {...}
      GlobalConfiguration.Configuration.Filters.Add(new MyExceptionFilter ());
      

      然后不调用MyExceptionFilter。但是,会调用ExceptionFilterAttribute的impl。

      然后我留下的是如何捕获http(WebApi的错误路径)和框架(不可解析的参数等)错误和异常。

      upd3:解决了。以下是我的解决方案的步骤。不幸的是,解决方案有点脆弱,需要一定的init步骤序列,而不是太容易出错:

      1. 在Application_Start中,在注册任何路由之前:

        GlobalConfiguration.Configuration.Services.Add(typeof(IExceptionLogger),new AuditExceptionLogger());

      2. 注册前端路线

      3. 注册WebApi路线
      4. 注册404处理程序并创建错误控制器

        RouteTable.Routes.MapHttpRoute(     名称:“Error404”,     routeTemplate:“{* url}”,     默认值:new {controller =“Error”,action =“Handle404”} );

      5. 实现DefaultHttpControllerSelector和ApiControllerActionSelector,在那里捕获异常并替换为

        GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector),new HttpNotFoundAwareDefaultHttpControllerSelector(GlobalConfiguration.Configuration)); GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpActionSelector),new HttpNotFoundAwareControllerActionSelector());

      6. 我还没有设计CustomError处理 - 我想向无效的前端请求显示正确的错误页面

1 个答案:

答案 0 :(得分:0)

您是否可以使用外部服务来捕获例外,例如Exceptionless?

https://exceptionless.com/