Estoy explorando la función Azure que se ejecuta en .net 5 y descubrí las nuevas capacidades de middleware .
He construido un middleware ficticio como este:
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); } } }En mi caso de uso, la función de Azure es una función activada por 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.."); } } En mi aplicación de función que se ejecuta en proceso en .net core 3.1 , cada función tenía la responsabilidad de detectar la excepción no controlada (a través de una clase base) y devolvía el código de estado HTTP apropiado.
Me gustaría tener esa lógica en un middleware para tenerla centralizada y evitar futuros errores.
Pregunta
El middleware detecta la excepción correctamente. Sin embargo, no veo cómo puedo alterar la respuesta y devolver algo más apropiado, en lugar de un 500 Internal Server Error que obtengo en este momento.
De acuerdo con este problema , actualmente no existe una implementación oficial al respecto, pero también mencionan una "solución alternativa" hasta que la funcionalidad adecuada se implemente directamente en las funciones de Azure.
Creamos un método de extensión para 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); } }El uso en el middleware se ve así:
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; } }