Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Azure Functions 2 - How to control json serialization settings

I want to be able to control how json is formatted when I return a content result from a Azure Function (V2). The following is a simplified version of what I am doing:

[FunctionName("CreateThing")]
public static async Task<IActionResult> CreateThingAsync([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "thing")]HttpRequest req, ILogger log)
{
    try{
        var result = await GetResultAsync(req);
        return new CreatedResult($"thing/{result.id}", result);
    }
    catch(ErrorException) {
        return new BadRequestObjectResult(e.Error);
    }
}

Is there a way to control how the results are formatted when they are returned, without using attributes on my models? I want to be able to use JsonSerializerSettings but I cant find a way of being able to configure this for the results that are returned as per the example above.

like image 562
Mark W Avatar asked Nov 12 '18 15:11

Mark W


1 Answers

Ran into the same problem myself today.

As Jerry commented, JsonResult can get you most of the way there; it supports a StatusCode property:

return new JsonResult(new WorkQueuedResponseMessage
{
    ...
}, Constants.CommunicationJsonSerializerSettings)
{
    StatusCode = StatusCodes.Status202Accepted,
};

For custom headers, my solution is a bit more hacky. I define my own IActionResult that just sticks headers onto another IActionResult:

private sealed class HeaderActionResult : IActionResult
{
    private readonly IActionResult _result;

    public HeaderActionResult(IActionResult result)
    {
        _result = result;
        HeaderDictionary = new HeaderDictionary();
        Headers = new ResponseHeaders(HeaderDictionary);
    }

    public IHeaderDictionary HeaderDictionary { get; }

    public ResponseHeaders Headers { get; }

    public async Task ExecuteResultAsync(ActionContext context)
    {
        foreach (var header in HeaderDictionary)
            context.HttpContext.Response.Headers.Append(header.Key, header.Value);
        await _result.ExecuteResultAsync(context);
    }
}

I can then define helper methods if desired:

public static IActionResult EnableCacheHeaders(this IActionResult response, TimeSpan time)
{
    return new HeaderActionResult(response)
    {
        Headers =
        {
            CacheControl = new CacheControlHeaderValue
            {
                Public = true,
                MaxAge = time,
            },
            Expires = DateTimeOffset.UtcNow + time,
        },
    };
}

and use them as such:

return new JsonResult(new WorkAlreadyCompletedResponseMessage
{
    ...
}, Constants.CommunicationJsonSerializerSettings).EnableCacheHeaders(TimeSpan.FromDays(1));

This works as a way to return IActionResult with custom JSON serialization, status codes, and headers, while using as many ASP.NET Core types as possible. Hopefully in the future we will get a better integration / injection story.

like image 85
Stephen Cleary Avatar answered Nov 09 '22 09:11

Stephen Cleary