2
votes

I am creating a function that reads a custom file in our storage. The function.json is similar to this one:

{
  "disabled": false,
  "bindings": [
    {
      "authLevel": "anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "route": "resource/{code}",
      "methods": [
        "get"
      ]
    },
    {
      "type": "blob",
      "name": "item",
      "path": "data/20171003/{code}.json",
      "connection": "blog_STORAGE",
      "direction": "in"
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    }
  ]
}

In postman, if I type an existing file, it will correctly invoke the function. If the file does not exists, on the other hand, the azure runtime will throw an error:

{ "id": "4ef77dcd-f8ed-4327-9447-969da6b328a9", "requestId": "0a9874dd-6a7b-4717-ae9f-c3c1e3bb16c8", "statusCode": 500, "errorCode": 0, "message": "Exception while executing function: Functions.func_ativos -> Valor não pode ser nulo.\r\nNome do parâmetro: stream", "errorDetails": "Microsoft.Azure.WebJobs.Host.FunctionInvocationException : Exception while executing function: Functions.func_ativos ---> System.ArgumentNullException : Valor não pode ser nulo.\r\nNome do parâmetro: stream\r\n at System.IO.StreamReader..ctor(Stream stream,Encoding encoding,Boolean detectEncodingFromByteOrderMarks,Int32 bufferSize,Boolean leaveOpen)\r\n at System.IO.StreamReader..ctor(Stream stream)\r\n
at Microsoft.Azure.WebJobs.Script.Binding.FunctionBinding.ConvertStreamToValue(Stream stream,DataType dataType,Object& converted)\r\n at async Microsoft.Azure.WebJobs.Script.Binding.FunctionBinding.BindStreamAsync(BindingContext context,FileAccess access)\r\n at async Microsoft.Azure.WebJobs.Script.Binding.ExtensionBinding.BindAsync(BindingContext context)\r\n at async Microsoft.Azure.WebJobs.Script.Description.NodeFunctionInvoker.ProcessInputBindingsAsync(Binder binder,Dictionary2 executionContext,Dictionary2 bindingData)\r\n
at async Microsoft.Azure.WebJobs.Script.Description.NodeFunctionInvoker.InvokeCore(Object[] parameters,FunctionInvocationContext context)\r\n at async Microsoft.Azure.WebJobs.Script.Description.FunctionInvokerBase.Invoke(Object[] parameters)\r\n at async Microsoft.Azure.WebJobs.Host.Executors.VoidTaskMethodInvoker2.InvokeAsync[TReflected,TReturnType](TReflected instance,Object[] arguments)\r\n at async Microsoft.Azure.WebJobs.Host.Executors.FunctionInvoker2.InvokeAsync[TReflected,TReturnValue](Object[] arguments)\r\n at async Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.InvokeAsync(IFunctionInvoker invoker,ParameterHelper parameterHelper,CancellationTokenSource timeoutTokenSource,CancellationTokenSource functionCancellationTokenSource,Boolean throwOnTimeout,TimeSpan timerInterval,IFunctionInstance instance)\r\n at async Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.ExecuteWithWatchersAsync(IFunctionInstance instance,ParameterHelper parameterHelper,TraceWriter traceWriter,ILogger logger,CancellationTokenSource functionCancellationTokenSource)\r\n at async Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.ExecuteWithLoggingAsync(??)\r\n at async Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.ExecuteWithLoggingAsync(??) \r\n End of inner exception\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n
at async Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.ExecuteWithLoggingAsync(??)\r\n at async Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.TryExecuteAsync(IFunctionInstance functionInstance,CancellationToken cancellationToken)\r\n at Microsoft.Azure.WebJobs.Host.Executors.ExceptionDispatchInfoDelayedException.Throw()\r\n at async Microsoft.Azure.WebJobs.JobHost.CallAsync(??)\r\n at async Microsoft.Azure.WebJobs.Script.ScriptHost.CallAsync(String method,Dictionary2 arguments,CancellationToken cancellationToken)\r\n at async Microsoft.Azure.WebJobs.Script.WebHost.WebScriptHostManager.HandleRequestAsync(FunctionDescriptor function,HttpRequestMessage request,CancellationToken cancellationToken)\r\n at async Microsoft.Azure.WebJobs.Script.WebHost.Controllers.FunctionsController.ProcessRequestAsync(HttpRequestMessage request,FunctionDescriptor function,CancellationToken cancellationToken)\r\n at async Microsoft.Azure.WebJobs.Script.WebHost.Controllers.FunctionsController.<>c__DisplayClass3_0.<ExecuteAsync>b__0(??)\r\n at async Microsoft.Azure.WebJobs.Extensions.Http.HttpRequestManager.ProcessRequestAsync(HttpRequestMessage request,Func3 processRequestHandler,CancellationToken cancellationToken)\r\n at async Microsoft.Azure.WebJobs.Script.WebHost.Controllers.FunctionsController.ExecuteAsync(HttpControllerContext controllerContext,CancellationToken cancellationToken)\r\n at async System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage request,CancellationToken cancellationToken)\r\n at async System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage request,CancellationToken cancellationToken)\r\n at async Microsoft.Azure.WebJobs.Script.WebHost.Handlers.SystemTraceHandler.SendAsync(HttpRequestMessage request,CancellationToken cancellationToken)\r\n at async Microsoft.Azure.WebJobs.Script.WebHost.Handlers.WebScriptHostHandler.SendAsync(HttpRequestMessage request,CancellationToken cancellationToken)\r\n at async System.Web.Http.HttpServer.SendAsync(HttpRequestMessage request,CancellationToken cancellationToken)" }

I want to send a 404 status code when the file is not found, not an ugly stack like that (and error 500). What is the best approach I should follow?

== update

Please note that FunctionInvocationException happens before my function is called. It seems an error in Azure Functions Runtime that I cannot know if is a bug or expected.

1

1 Answers

0
votes

We also could catch the exception in the Azure function App. In your case you could catch the exception and return the http status code HttpStatusCode.NotFound

 public static HttpResponseMessage Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
        {
            log.Info("C# HTTP trigger function processed a request.");

            try
            {
                //Todo :Add your own logic
            }
            catch (Exception ex)
            {
                return req.CreateResponse(HttpStatusCode.NotFound);
            }
            return req.CreateResponse(HttpStatusCode.OK);
        }

Edit:

As you mentioned that it happens before the function is called, it seems that returned by Azure function integrated SDK. It perhaps is by designed. We also could give our idea to azure function team.

If we want to control the logic, my work around is that we could remove the input blob and implement the customized logic ourselves. We could get the sample code from the Microsoft Azure Storage SDK for Node.js.

enter image description here