【问题标题】:Azure Function Middleware: How to return a custom HTTP response?Azure 函数中间件:如何返回自定义 HTTP 响应?
【发布时间】:2021-09-21 18:38:35
【问题描述】:

我正在探索在 .net 5 上运行的 Azure Function,我发现了新的 middleware capabilities

我已经构建了一个像这样的虚拟中间件:

public sealed class ExceptionLoggingMiddleware : IFunctionsWorkerMiddleware
{
    private readonly ILogger<ExceptionLoggingMiddleware> m_logger;

    public ExceptionLoggingMiddleware(ILogger<ExceptionLoggingMiddleware> logger)
    {
        m_logger = logger;
    }

    public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
    {
        try
        {
            await next(context);
        }
        catch (Exception unhandledException)
        {
            m_logger.LogCritical(unhandledException, "Unhandled exception caught: {UnhandledException}", unhandledException.Message);
        }
    }
}

在我的用例中,Azure 函数是一个 HTTP 触发函数:

public sealed class StorageAccountsFunction
{
    private readonly ILogger<StorageAccountsFunction> m_logger;

    public StorageAccountsFunction
    (
        ILogger<StorageAccountsFunction> logger
    )
    {
        m_logger = logger;
    }

    [Function("v1-post-storage-account")]
    public async Task<HttpResponseData> CreateAsync
    (
        [HttpTrigger(AuthorizationLevel.Anonymous, "POST", Route = "v1/storage-accounts")] 
        HttpRequestData httpRequestData, 
        FunctionContext context
    )
    {
        m_logger.LogInformation("Processing a request to create a new storage account");

        throw new Exception("Oh no! Oh well..");
    }
}

在我在.net core 3.1 上运行的函数应用程序中,每个函数都有责任(通过基类)捕获未处理的异常并返回适当的 HTTP 状态代码。

我希望将该逻辑放在中间件中,而不是将其集中化并避免将来出现任何错误。

问题

异常被中间件正确捕获。但是,我看不到如何更改响应并返回更合适的内容,而不是我现在得到的 500 Internal Server Error

【问题讨论】:

    标签: c# azure azure-functions .net-5 asp.net-core-middleware


    【解决方案1】:

    根据this issue,目前没有关于此的官方实现,但他们也提到了一个“hacky workaround”,直到将正确的功能直接实现到 Azure 函数中

    我们为 FunctionContext 创建了一个扩展方法:

    internal static class FunctionUtilities
    {
        internal static HttpRequestData GetHttpRequestData(this FunctionContext context)
        {
            var keyValuePair = context.Features.SingleOrDefault(f => f.Key.Name == "IFunctionBindingsFeature");
            var functionBindingsFeature = keyValuePair.Value;
            var type = functionBindingsFeature.GetType();
            var inputData = type.GetProperties().Single(p => p.Name == "InputData").GetValue(functionBindingsFeature) as IReadOnlyDictionary<string, object>;
            return inputData?.Values.SingleOrDefault(o => o is HttpRequestData) as HttpRequestData;
        }
    
        internal static void InvokeResult(this FunctionContext context, HttpResponseData response)
        {
            var keyValuePair = context.Features.SingleOrDefault(f => f.Key.Name == "IFunctionBindingsFeature");
            var functionBindingsFeature = keyValuePair.Value;
            var type = functionBindingsFeature.GetType();
            var result = type.GetProperties().Single(p => p.Name == "InvocationResult");
            result.SetValue(functionBindingsFeature, response);
        }
    }
    

    中间件中的用法是这样的:

    public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
    {
       try
       {
           await next(context);
       }
       catch (Exception ex)
       {
           if (ex.InnerException is *NameOfExceptionYouNeed* e)
           {
               var req = context.GetHttpRequestData();
               var res = await req.ErrorResponseAsync(e.Message);
               context.InvokeResult(res);
               return;
           }
    
           throw;
       }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-10
      • 1970-01-01
      • 2023-03-18
      • 1970-01-01
      • 2019-10-28
      • 1970-01-01
      • 2018-08-24
      相关资源
      最近更新 更多