自定义IExceptionHandler

Ste*_*ary 10 c# azure azure-functions

我正在尝试IExceptionHandler使用我的Azure功能(C#类库).我的想法是拥有自己的异常处理程序,用于包含我自己的内存中跟踪日志的意外异常; 澄清一下,我确实希望将这些发送到客户端浏览器并显示给用户.

细节如下.

使用这个简单的自定义异常处理

public sealed class CustomExceptionHandler : ExceptionHandler
{
  public override void Handle(ExceptionHandlerContext context)
  {
    context.Result = new ResponseMessageResult(
        context.Request.CreateErrorResponse(HttpStatusCode.BadRequest,
            "custom message string"));
  }
}
Run Code Online (Sandbox Code Playgroud)

我试过安装它:

[FunctionName("Function1")]
public static HttpResponseMessage Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "works")]
    HttpRequestMessage req)
{
  req.GetConfiguration().Services.Replace(typeof(IExceptionHandler),
      new CustomExceptionHandler());
  throw new Exception("unexpected exception");
}
Run Code Online (Sandbox Code Playgroud)

但是在部署时,我只是得到通用的"操作失败"错误消息(例如,从Chrome格式化XML):

<ApiErrorModel xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/Microsoft.Azure.WebJobs.Script.WebHost.Models">
  <Arguments xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" i:nil="true"/>
  <ErrorCode>0</ErrorCode>
  <ErrorDetails i:nil="true"/>
  <Id>dec07825-cf4e-49cc-a80e-bef0dbd01ba0</Id>
  <Message>An error has occurred. For more information, please check the logs for error ID dec07825-cf4e-49cc-a80e-bef0dbd01ba0</Message>
  <RequestId>51df1fec-c1c2-4635-b82c-b00d179d2e50</RequestId>
  <StatusCode>InternalServerError</StatusCode>
</ApiErrorModel>
Run Code Online (Sandbox Code Playgroud)

如果我Diagnostic Logs -> Detailed error messages在AF UI中打开并尝试确保始终写入详细的错误消息:

[FunctionName("Function1")]
public static HttpResponseMessage Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "works")]
    HttpRequestMessage req)
{
  req.GetRequestContext().IncludeErrorDetail = true;
  req.GetRequestContext().IsLocal = true;
  req.GetConfiguration().Services.Replace(typeof(IExceptionHandler),
      new CustomExceptionHandler());
  throw new Exception("unexpected exception");
}
Run Code Online (Sandbox Code Playgroud)

然后我得到异常细节,但显然仍然由内置异常处理程序(从Chrome格式化XML)处理:

<ApiErrorModel xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/Microsoft.Azure.WebJobs.Script.WebHost.Models">
  <Arguments xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" i:nil="true"/>
  <ErrorCode>0</ErrorCode>
  <ErrorDetails>Microsoft.Azure.WebJobs.Host.FunctionInvocationException : Exception while executing function: Function1 ---> System.Exception : unexpected exception at ...</ErrorDetails>
  <Id>5e752375-002b-4ab7-a348-20edad64a3fe</Id>
  <Message>Exception while executing function: Function1 -> unexpected exception</Message>
  <RequestId>b6611456-f3f1-4591-97e4-920dae59b5ff</RequestId>
  <StatusCode>InternalServerError</StatusCode>
</ApiErrorModel>
Run Code Online (Sandbox Code Playgroud)

所以这是暴露堆栈跟踪和异常消息,但我没有内存中的跟踪日志.

我想要做的是自己创建意外异常的响应消息.例如,这是我的自定义错误响应对于预期的异常(来自Postman的JSON格式):

{
  "message": "An error has occurred.",
  "exceptionMessage": "Could not find package `nito.bob`",
  "exceptionType": "Common.ExpectedException",
  "stackTrace": "   at ...",
  "log": [
    "Received request for jsonVersion=4, packageId=`nito.bob`, packageVersion=``, targetFramework=``",
    "Looking up latest package version for `nito.bob`",
    "No non-prerelease package version found for `nito.bob`; looking up latest prerelease package version",
    "No package version found for `nito.bob`",
    "Returning 404: Could not find package `nito.bob`"
  ],
  "requestId": "b2df08cb-1071-4e47-bd24-bf74152e4b2a"
}
Run Code Online (Sandbox Code Playgroud)

这只是HttpError我用log和扩充的基本格式化异常(有详细信息)requestId.由于这是一个预期的例外,这不是在一个IExceptionHandler; 我刚回来了HttpResponseMessage.

有趣的部分:当我在本地托管AF时,我的自定义IExceptionHandler工作正常.它在部署时不起作用.如果我接受代码并在本地运行它,我会收到我期望的响应(来自Postman的JSON格式):

{
  "Message": "custom message string"
}
Run Code Online (Sandbox Code Playgroud)

替代方法对我不起作用:

  • 捕获所有Exceptions并返回HttpRequestMessage.CreateErrorResponse.我已经为预期的例外做了这个,这很好.对于意外异常,这不是一个好的解决方案,因为我希望功能执行明确标记为"失败".返回HttpResponseMessage(即使使用500状态代码)AF运行时将其视为"成功",并且在仪表板或日志中未显示为"失败"(或者可能是App Insights,但我没有明确检查过) .

Gle*_*rie 1

我想你正在寻找的是FunctionExceptionFilterAttribute

以下是如何实现抽象类的简单代码示例:

public class YourErrorHandlerAttribute : FunctionExceptionFilterAttribute
{
    public override async Task OnExceptionAsync(FunctionExceptionContext exceptionContext, CancellationToken cancellationToken)
    {
        var fn_name = exceptionContext.FunctionName;
        var fn_instanceId = exceptionContext.FunctionInstanceId;
        var ex = exceptionContext.Exception;

        // TODO: your logic here.
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是如何在您的函数中使用它:

[FunctionName("Function1")]
[YourErrorHandler]
public static HttpResponseMessage Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "works")]
HttpRequestMessage req)
{
     // TODO: your Azure Function logic / implementation.
}
Run Code Online (Sandbox Code Playgroud)

它的行为类似于ActionFilterAttributeASP.NET MVC