Azure Functions Programming Model for C#

This document details the programming model for developing Azure Functions using C#. It covers triggers, bindings, and the core concepts for building serverless applications on Azure.

Understanding the Core Concepts

Azure Functions provide a serverless compute service that allows you to run small pieces of code, called "functions," without managing infrastructure. The C# programming model leverages .NET to enable rich development experiences.

Triggers and Bindings

Functions are initiated by triggers, which are events that signal a function should run. Bindings allow your function to connect to other Azure services and data sources declaratively, simplifying input and output operations.

Function Anatomy

A C# Azure Function typically consists of:

Developing with C#

You can develop Azure Functions with C# using various tools, including Visual Studio, Visual Studio Code, and the Azure CLI.

Trigger and Binding Attributes

The core of the programming model lies in the use of attributes. Here's an example of an HTTP-triggered function that reads a query parameter and writes to a storage queue:

using System;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

public static class HttpTriggerExample
{
    [FunctionName("HttpTriggerCSharp")]
    public static async Task Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
        [Queue("myqueue-items", Connection = "AzureWebJobsStorage")] IAsyncCollector<string> queueCollector,
        ILogger log)
    {
        log.LogInformation("C# HTTP trigger function processed a request.");

        string name = req.Query["name"];

        string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
        dynamic data = JsonConvert.DeserializeObject(requestBody);
        name = name ?? data?.name;

        if (name != null)
        {
            string responseMessage = $"Hello, {name}. This HTTP triggered function executed successfully. Sending message to queue.";
            await queueCollector.AddAsync($"Processed: {name}");
            return new OkObjectResult(responseMessage);
        }
        else
        {
            return new BadRequestObjectResult("Please pass a name on the query string or in the request body");
        }
    }
}

Common Triggers and Bindings

Trigger/Binding Description Attribute Example
HTTP Trigger Initiates function execution via HTTP requests. [HttpTrigger(AuthorizationLevel.Function, "get")]
Timer Trigger Executes a function on a schedule. [TimerTrigger("0 */5 * * * *")]
Blob Storage Input Reads data from Azure Blob Storage. [Blob("container/{name}.txt")] string blobContent
Blob Storage Output Writes data to Azure Blob Storage. [Blob("output-container/{name}.txt")] out string blobOutput
Queue Storage Input Reads messages from an Azure Storage Queue. [QueueTrigger("myqueue")] string myQueueItem
Queue Storage Output Writes messages to an Azure Storage Queue. [Queue("output-queue")] out string queueOutput
Cosmos DB Input Reads documents from Cosmos DB. [CosmosDB(databaseName: "db", collectionName: "items", ConnectionStringSetting = "CosmosDBConnection")] IEnumerable<MyDocument> items

Dependency Injection

Azure Functions in .NET support dependency injection, allowing you to inject services like configuration, logging, and custom services into your functions. This is configured in your `Startup.cs` file.

Note: For .NET 6 and later, you can use the in-process model for better performance and a more integrated .NET experience.

Best Practices

Tip: For long-running operations, explore Durable Functions, which extend Azure Functions with stateful workflows.

Further Reading