【问题标题】:Filter Exception Stack Trace from Web API Error?从 Web API 错误中过滤异常堆栈跟踪?
【发布时间】:2015-06-03 07:40:26
【问题描述】:

我有一个与之通信的 web api。

发生异常时,我得到以下 JSON 模板:

{
  "Message": "An error has occurred.",
  "ExceptionMessage": "Index was outside the bounds of the array.",
  "ExceptionType": "System.IndexOutOfRangeException",
  "StackTrace": "   at WebApiTest.TestController.Post(Uri uri) in c:\\Temp\\WebApiTest\\WebApiTest\\TestController.cs:line 18\r\n   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClassf.<GetExecutor>b__9(Object instance, Object[] methodParameters)\r\n   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)\r\n   at System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1 func, CancellationToken cancellationToken)"
}

我希望 JSON 包含的只是“Message”和“ExceptionMessage”属性,但仍然可以控制按需返回完整的堆栈跟踪。

我尝试过使用

GlobalConfiguration.Configuration.IncludeErrorDetailPolicy

但似乎全有或全无,要么只是单个“消息”属性,要么在将其设置为“始终”时获取完整对象。

有什么简单的方法可以实现吗?

我们将不胜感激。

【问题讨论】:

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


    【解决方案1】:

    在我的代码中,我使用异常过滤器来满足您的要求,请查看以下两个链接了解更多详情

    Web API Exception Handling

    Web API global error handling

    我们在代码中做了如下:

    1. 创建异常过滤器:

      public class ViewRExceptionFilterAttribute : ExceptionFilterAttribute
      {
      // Global context message for the modifying the context response in case of exception
      private string globalHttpContextMessage;
      
      /// <summary>
      ///     Overriding the OnException method as part of the Filter, which would detect the type of Action and would
      ///     accordingly modify the Http
      ///     context response
      /// </summary>
      /// <param name="context"></param>
      public override void OnException(HttpActionExecutedContext context)
      {
          // Dictionary with Type and Action for various Type actions, current method is called by various types
          Dictionary<Type, Action> dictionaryExceptionTypeAction = new Dictionary<Type, Action>();
      
          // Add an action for a given exception type
          dictionaryExceptionTypeAction.Add(typeof (ViewRClientException), ViewRClientExceptionAction(context.Exception));            
          dictionaryExceptionTypeAction.Add(typeof (Exception), SystemExceptionAction(context.Exception));
      
          // Execute an Action for a given exception type
          if (context.Exception is ViewRClientException)
              dictionaryExceptionTypeAction[typeof (ViewRClientException)]();
         else
              dictionaryExceptionTypeAction[typeof (Exception)]();
      
          // Reset the Context Response using global string which is set in the Exception specific action
          context.Response = new HttpResponseMessage
          {
              Content = new StringContent(globalHttpContextMessage)
          };
      }
      
      /// <summary>
      ///     Action method for the ViewRClientException, creates the Exception Message, which is Json serialized
      /// </summary>
      /// <returns></returns>
      private Action ViewRClientExceptionAction(Exception viewRException)
      {
          return (() =>
          {
              LogException(viewRException);
      
              ViewRClientException currentException = viewRException as ViewRClientException;
      
              ExceptionMessageUI exceptionMessageUI = new ExceptionMessageUI();
      
              exceptionMessageUI.ErrorType = currentException.ErrorTypeDetail;
      
              exceptionMessageUI.ErrorDetailList = new List<ErrorDetail>();
      
              foreach (ClientError clientError in currentException.ClientErrorEntity)
              {
                  ErrorDetail errorDetail = new ErrorDetail();
      
                  errorDetail.ErrorCode = clientError.ErrorCode;
      
                  errorDetail.ErrorMessage = clientError.ErrorMessage;
      
                  exceptionMessageUI.ErrorDetailList.Add(errorDetail);
              }
      
              globalHttpContextMessage = JsonConvert.SerializeObject(exceptionMessageUI, Formatting.Indented);
          });
      }
      

    这里的 ViewRClientException 是我的自定义异常类,具有以下架构:

    public class ViewRClientException : Exception
    {
        public ViewRClientException(ErrorType errorType, List<ClientError> errorEntity)
        {
            ErrorTypeDetail = errorType;
            ClientErrorEntity = errorEntity;
        }
    
        public ErrorType ErrorTypeDetail { get; private set; }
        public List<ClientError> ClientErrorEntity { get; private set; }
    }
    

    上面定义的Action方法确保我们得到相关的Json序列化字符串,可以作为Json响应,类似SystemExceptionAction对任何通用异常的工作,不是自定义的。事实上,我还有许多其他自定义异常类别。当前过滤器修改了 HttpContext.Response

    1. 在WebAPIConfig.cs中注册Exception过滤器,如下图:

        public static class WebApiConfig
          {
            public static void Register(HttpConfiguration config)
            {
              // Web API configuration and services
      
              // Adding the Generic Exception Filter for the application
              config.Filters.Add(new ViewRExceptionFilterAttribute());
      
              // Web API routes
              config.MapHttpAttributeRoutes();
      
              config.Routes.MapHttpRoute("ControllerActionApi", "api/{controller}/{action}/{userID}",
                  new {userID = RouteParameter.Optional}
                  );
      
              config.Routes.MapHttpRoute("ControllerApi", "api/{controller}/{userID}",
                  new {userID = RouteParameter.Optional}
                  );
            }
         }
      

    现在它应该可以根据需要提供自定义消息了

    【讨论】:

    • 谢谢,我会调查的。
    • 对我来说它完美无缺。您可以使用自定义异常来获得所需格式的数据的基本要求
    【解决方案2】:

    不完整的例子。 ClientError & ErrorType ErrorTypeDetail

    如果您要贡献,请包括所有内容!

    【讨论】:

    • 请使用 cmets 的“评论”链接并保存实际答案的“答案”链接
    猜你喜欢
    • 2011-01-05
    • 2017-08-06
    • 2010-09-13
    • 2011-08-10
    • 2018-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多