18

After migrating my Azure Functions project to .NET 5, it has started wrapping my responses in a weird wrapper class.

For instance, consider the following endpoint:

public record Response(string SomeValue);

[Function("Get")]
public async Task<IActionResult> Get(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "get-something")]
    HttpRequestData request)
{
    return new OkObjectResult(new Response("hello world"));
}

Before, it would return:

{
    "someValue": "hello world"
}

But now, it returns:

{
  "Value": {
    "SomeValue": "hello world"
  },
  "Formatters": [],
  "ContentTypes": [],
  "DeclaredType": null,
  "StatusCode": 200
}

I get that it must be because it just tries to serialize the object result, but I can't find any documentation on how this is supposed to work in .NET 5.

My main function currently looks like this:

public static async Task Main()
{
    var host = new HostBuilder()
        .ConfigureFunctionsWorkerDefaults(x => 
            x.UseDefaultWorkerMiddleware())
        .ConfigureAppConfiguration((_, builder) => builder
            .AddJsonFile("local.settings.json", true)
            .Build())
        .ConfigureServices(ConfigureServices)
        .Build();

    await host.RunAsync();
}

My project is located here, in case someone are interested: https://github.com/sponsorkit/sponsorkit.io

Currently, my .NET 5 work is on a branch called feature/signup-flow.

Mathias Lykkegaard Lorenzen
  • 15,031
  • 23
  • 100
  • 187

5 Answers5

17

Using IActionResult with Azure Functions in .NET 5?

You can't return IActionResult with Azure Functions in .NET 5. Or more generally, you can't return IActionResult with Azure Functions using the isolated process model. Quote from the docs:

For HTTP triggers, you must use HttpRequestData and HttpResponseData to access the request and response data. This is because you don't have access to the original HTTP request and response objects when running out-of-process.

Instead of IActionResult, you need to return HttpResponseData. Example code is here.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • That seems like an insane compromise at first glance. Is there any way to work around this? I would really hate to lose all my strong-typing etc. – Mathias Lykkegaard Lorenzen Apr 11 '21 at 14:33
  • @MathiasLykkegaardLorenzen: I'm not sure. I expect over time better supporting APIs will be available. The isolated process model for .NET is quite new right now ([one month](https://techcommunity.microsoft.com/t5/apps-on-azure/net-on-azure-functions-roadmap/ba-p/2197916)). I haven't adopted it yet because I need durable functions, which are also not supported yet. – Stephen Cleary Apr 11 '21 at 14:53
  • That's a pretty simplistic sample - just returning a string. What about objects and lists of objects? So you would have to deserialize any objects before sending? – inliner49er Jun 05 '21 at 20:49
  • @inliner49er: For now, yes. A lot of the ASP.NET pipeline helpers are not available yet. Things like serialization and content negotiation you have to build yourself. – Stephen Cleary Jun 05 '21 at 22:41
10

To return an object from .NET 5 Azure Functions, use the following code:

var response = req.CreateResponse(HttpStatusCode.OK);
await response.WriteAsJsonAsync(obj);
return response;
Niels Brinch
  • 3,033
  • 9
  • 48
  • 75
0

For Azure Functions with .NET 7 we can just return the List or Object directly from the function and let the runtime handle the JSON serialization.

It might be necessary to adjust the global JSON settings to set camelCase etc.

Thomas
  • 4,030
  • 4
  • 40
  • 79
-1

Was pleasantly surprised to find that returning Task from a "dotnet-isolated" function workins in Core 6. Saved me a few hours as I do not need to change to Task in a number of functions

Alexa Goldi
  • 19
  • 1
  • 2
-1

After searching around and wanting to stay in the context of the IActionResult object, I ended up leveraging the ObjectResult object so that I can standardize all the service responses with the standardize JSON messages.

Jeff Blumenthal
  • 442
  • 6
  • 8