skip to Main Content

I have the following function that should return either a 200 response with a book as payload or a 404 with empty body:

using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Http;
using Microsoft.Azure.Functions.Worker;

public class Function1
{
    private readonly ILogger<Function1> _logger;

    public Function1(ILogger<Function1> logger)
    {
        _logger = logger;
    }
    private static readonly Dictionary<string, string> items = new Dictionary<string, string>
    {
    { "1", "Book 1" },
    { "2", "Book 2" },
    { "3", "Book 3" }
    };

    [Function("GetItem2")]
    public async Task<IActionResult> GetItemAsync([HttpTrigger(AuthorizationLevel.Function, "get", Route = "GetItem2/{id}")] HttpRequest request,
    string id,
    CancellationToken c)
    {
        _logger.LogInformation($"Received request for item with id: {id}");

        await Task.Delay(100, c);
        if (items.TryGetValue(id, out var item))
        {
            return new OkObjectResult(item);
        }
        else
        {
            return new NotFoundResult();
        }

    }
}

It works as expected in .NET 6 and running on Azure functions with the in-process model.

I am upgrading it to .NET 8 and an isolated worker model, and now response changed! it always returns 200, with the request details in the payload:
existing book response
non-existing book response
I wonder what caused this change in behaviour and how do I fix it? Of course I do not want to wrap http statuses in the response payload.

I am using the following Program.cs:

var host = new HostBuilder()
    .ConfigureAppConfiguration((context, config) =>
    {
        config.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true);
        config.AddEnvironmentVariables();
    })
    .ConfigureFunctionsWorkerDefaults()
    .ConfigureServices(ConfigureServices)
    .ConfigureLogging((context, logging) =>
    {
        logging.AddConfiguration(context.Configuration.GetSection("Host:Logging"));
    })
    .Build();

host.Run();

static void ConfigureServices(HostBuilderContext builderContext, IServiceCollection serviceCollection)
{
}

2

Answers


  1. Chosen as BEST ANSWER

    Turns out replacing ConfigureFunctionsWorkerDefaults() with ConfigureFunctionsWebApplication() fixes my problem. I do not know what these function does and why the first gives broken http responses. Would love if someone could explain a bit!


  2. I have modified your code as below and it worked:

    Function.cs:

    public class Function1
    {
        private readonly ILogger<Function1> _logger;
    
        public Function1(ILogger<Function1> logger)
        {
            _logger = logger;
        }
        private static readonly Dictionary<string, string> items = new Dictionary<string, string>
        {
        { "1", "Book 1" },
        { "2", "Book 2" },
        { "3", "Book 3" }
        };
    
        [Function("GetItem")]
        public async Task<IActionResult> GetItemAsync([HttpTrigger(AuthorizationLevel.Function, "get", Route = "GetItem/{id}")] HttpRequest request,
        string id,
        CancellationToken c)
        {
            _logger.LogInformation($"Received request for item with id: {id}");
    
            await Task.Delay(100, c);
            if (items.TryGetValue(id, out var item))
            {
                return new OkObjectResult(item);
            }
            else
            {
                return new NotFoundResult();
            }
    
        }
    }
    

    Update:

    • When you integrate Isolated Azure function with Asp.Net core integration, you have to update the host builder configuration to call ConfigureFunctionsWebApplication() in Program.cs, refer MSDOC.

    Program.cs:

    using Microsoft.Azure.Functions.Worker.Builder;
    using Microsoft.Extensions.Hosting;
    
    var builder = FunctionsApplication.CreateBuilder(args);
    
    builder.ConfigureFunctionsWebApplication();
    
    builder.Build().Run();
    

    Output when item not found:

    enter image description here

    Functions:
    
            GetItem: [GET] http://localhost:7180/api/GetItem/{id}
    
    For detailed output, run func with --verbose flag.
    [2025-01-09T05:08:50.926Z] Host lock lease acquired by instance ID '000000000000000000000000F72731CC'.
    [2025-01-09T05:08:51.930Z] Executing 'Functions.GetItem' (Reason='This function was programmatically called via the host APIs.', Id=8e5947ce-d529-4f67-b081-361404ed97f4)
    [2025-01-09T05:08:52.208Z] Received request for item with id: 4
    [2025-01-09T05:08:52.319Z] Executing StatusCodeResult, setting HTTP status code 404
    [2025-01-09T05:08:52.382Z] Executed 'Functions.GetItem' (Succeeded, Id=8e5947ce-d529-4f67-b081-361404ed97f4, Duration=481ms)
    

    Output when Item found:

    enter image description here

    Functions:
    
            GetItem: [GET] http://localhost:7180/api/GetItem/{id}
    
    For detailed output, run func with --verbose flag.
    [2025-01-09T05:20:12.474Z] Host lock lease acquired by instance ID '000000000000000000000000F72731CC'.
    [2025-01-09T05:20:14.715Z] Executing 'Functions.GetItem' (Reason='This function was programmatically called via the host APIs.', Id=81dd75a1-7167-4169-a3f0-8b4d88f13dc2)
    [2025-01-09T05:20:15.015Z] Received request for item with id: 2
    [2025-01-09T05:20:15.145Z] Executing OkObjectResult, writing value of type 'System.String'.
    [2025-01-09T05:20:15.226Z] Executed 'Functions.GetItem' (Succeeded, Id=81dd75a1-7167-4169-a3f0-8b4d88f13dc2, Duration=537ms)
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search