Search code examples
c#jsonazure-functions.net-5

Azure Function with HTTP trigger fails to bind model from JSON payload (.NET 5 out-of-proc )


I am running an isolated process function that is failing to bind the input model from the JSON payload.

This is my function:

[Function("AddChip")]
public async Task<HttpResponseData> AddChip([HttpTrigger(AuthorizationLevel.Anonymous,
 "post", Route = "chip")] Chip chip, HttpRequestData req, FunctionContext executionContext)
{
            
    var logger = executionContext.GetLogger("Function1");
    logger.LogInformation("C# HTTP trigger function processed a request.");

    var result = await _chipService.UpsertChipAsync(chip);

    var response = req.CreateResponse(HttpStatusCode.OK);
    await response.WriteAsJsonAsync(result);
    return response;
}

And this is my Chip class:

public class Chip
{
    public string Id {  get; set; }
    public double Balance { get; set; }
    public DateTime Created { get; set; }
    public DateTime Updated { get; set; }
}

But when I call it from Insomnia making sure the Content-Type application/json header is set with this body:

{
    "Id": "1",
    "Balance": 0,
    "Created": "2001-01-01T00:00:00",
    "Updated": "2001-01-01T00:00:00"
}

I get an error message saying that the chip parameter could not be converted:

Microsoft.Azure.Functions.Worker.Diagnostics.Exceptions.FunctionInputConverterException: Error converting 1 input parameters for Function 'AddChip': Cannot convert input parameter 'chip' to type 'Models.Chip' from type 'Microsoft.Azure.Functions.Worker.GrpcHttpRequestData'.

I have tried unsuccessfully:

  • Removing the HttpRequestData parameter,
  • Different classes and payloads,
  • Different AuthorizationLevel

It seems related to gRPC somehow as the error references GrpcHttpRequestData.

Different sources like Microsoft documentation or this Rick van den Bosch post or even other Stack Overflow answers like Azure Functions model binding imply this should work, but it does not.


Solution

  • As Stephen mentioned in the other answer, there is no fully fledged model binding capability today in the .net 5 azure function(out of process model). Your request payload is available in the Body property of the HttpRequestData instance and you may de-serialize it inside your function.

    The below example uses JsonSerializer from System.Text.Json namespace.

    static JsonSerializerOptions SerializerOptions = new JsonSerializerOptions
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        PropertyNameCaseInsensitive = true
    };
    
    [Function("AddChip")]
    public async Task<HttpResponseData> AddChip(
        [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "chip")] HttpRequestData req,
        FunctionContext executionContext)
    {
        Chip chip = null;
    
        if (req.Body is not null)
        {
            chip = await JsonSerializer.DeserializeAsync<Chip>(req.Body, SerializerOptions);
        }
    
        var logger = executionContext.GetLogger("Function1");
        logger.LogInformation("C# HTTP trigger function processed a request for." + chip?.Id);
    
        var result = await _chipService.UpsertChipAsync(chip);
    
        var response = req.CreateResponse(HttpStatusCode.OK);
        await response.WriteAsJsonAsync(result);
        return response;
    }