Azure Functions: Inherit HttpTrigger functions / routes from base class

Viewed 38

I've got some common functionality in a number of Azure Function Apps. Each Function App exposes the exact same query operations on a common resource that each Function App has. Same endpoints, same dependancies etc. Up until now, there's been a lot of copy paste keeping this going.

So I refactored it out into a base abstract class that lives in a common project consumed by all services. It looks like this:

    public abstract class DeadLetterApiBaseFunction : BaseFunction
    {
        private readonly IDeadLetterBlobClient _deadLetterBlobClient;
        private readonly string ROLE_READ;
        private readonly string ROLE_WRITE;
        private readonly ILogger _logger;

        public DeadLetterApiBaseFunction(
            ILogger logger,
            IMiddlewareService middleware,
            IDeadLetterBlobClient deadLetterBlobClient,
            string ROLE_READ,
            string ROLE_WRITE) : base(logger, middleware)
        {
            _logger = logger;
            _deadLetterBlobClient = deadLetterBlobClient;
            this.ROLE_READ = ROLE_READ;
            this.ROLE_WRITE = ROLE_WRITE;
        }

        [FunctionName(nameof(GetDeadLetterBlobItemsForContainer))]
        [ProducesResponseType(typeof(ResponsePayload<List<BlobItemWithContent>>), Status200OK)]
        [ProducesResponseType(Status500InternalServerError)]
        [ProducesResponseType(Status400BadRequest)]
        [QueryStringParameter("container", "Name of the container", DataType = typeof(string))]
        public async Task<ActionResult<ResponsePayload<List<BlobItemWithContent>>>> GetDeadLetterBlobItemsForContainer(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "v1/dead-letters/blobs-for-container")]
            HttpRequest request)
        {
            // .... do stuff 
        }
    }
}

The idea being that each service will subclass this like so:

    public class DeadLetterApiFunction : DeadLetterApiBaseFunction
    {
        public DeadLetterApiFunction(
            ILogger<DeadLetterApiFunction> logger,
            IMiddlewareService middleware,
            IDeadLetterBlobClient deadLetterBlobClient) : base(
                logger: logger, 
                middleware: middleware, 
                deadLetterBlobClient: deadLetterBlobClient,
                ROLE_READ: "blarg",
                ROLE_WRITE: "blarg2")
        {
        }
    }

Looks great right? However, when you run the function, the endpoints are not being exposed - the functions are not being detected.

Is there a way to get Azure Functions HttpTrigger functions exposed from a base class? Or is that just not supported? We're using .NET Core 3.1 and Azure Functions 3.

There's a related question here, but the answer took a different path:

Use Azure Functions in abstract base class?

1 Answers

As an HTTP trigger is a single point of entry for a specific route, I would abstract out the HTTP trigger in a separate class and then inject it in the DeadLetterApiFunction class upon creation as a Singleton via the Startup.cs file. This is possible as Azure functions support instance functions to enable DI.

public class HttpTrigger
{
    public HttpTrigger()
    {
    }

    [FunctionName(nameof(GetDeadLetterBlobItemsForContainer))]
    [ProducesResponseType(typeof(ResponsePayload<List<BlobItemWithContent>>), Status200OK)]
    [ProducesResponseType(Status500InternalServerError)]
    [ProducesResponseType(Status400BadRequest)]
    [QueryStringParameter("container", "Name of the container", DataType = typeof(string))]
    public async Task<ActionResult<ResponsePayload<List<BlobItemWithContent>>>> GetDeadLetterBlobItemsForContainer(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "v1/dead-letters/blobs-for-container")]
        HttpRequest request)
    {
        // .... do stuff 
    }
}
Related