Back to blog
cloudbeginner

Your First Azure Function — HTTP Trigger in C#

Build and deploy your first Azure Function with an HTTP trigger in C#. Understand triggers, bindings, the function host, local development, and deployment to Azure.

Asma HafeezApril 17, 20264 min read
azureazure-functionsserverlesscsharpdotnet
Share:š•

Your First Azure Function

Azure Functions is serverless compute: you write a function, Azure runs it when triggered. You pay only when it executes. No VMs, no App Service plans (on the Consumption tier).


Setup

Bash
# Install the Azure Functions Core Tools
npm install -g azure-functions-core-tools@4 --unsafe-perm true

# Create a new C# function project
func init MyFunctions --worker-runtime dotnet-isolated

cd MyFunctions

# Add an HTTP trigger function
func new --name Hello --template "HTTP trigger" --authlevel anonymous

The --worker-runtime dotnet-isolated uses the isolated worker model (recommended for .NET 8+): your code runs in a separate process, giving full .NET 8 support and simpler dependency injection.


The HTTP Trigger Function

C#
// Hello.cs — generated by func new
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;

public class Hello(ILogger<Hello> logger)
{
    [Function("Hello")]
    public async Task<HttpResponseData> Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req)
    {
        logger.LogInformation("Hello function triggered");

        var name = req.Query["name"] ?? "World";

        var response = req.CreateResponse(HttpStatusCode.OK);
        await response.WriteStringAsync($"Hello, {name}!");
        return response;
    }
}

Run locally:

Bash
func start
# GET http://localhost:7071/api/Hello?name=Alice  →  Hello, Alice!

Anatomy of a Function

[Function("FunctionName")]      — registers the function with the host
[HttpTrigger(...)]              — what triggers this function
AuthorizationLevel              — Anonymous / Function / Admin
"get", "post"                   — accepted HTTP methods
HttpRequestData req             — the incoming request
HttpResponseData                — the response you return

Reading the Request Body

C#
[Function("CreateProduct")]
public async Task<HttpResponseData> CreateProduct(
    [HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req)
{
    var body = await req.ReadFromJsonAsync<CreateProductRequest>();

    if (body is null || string.IsNullOrWhiteSpace(body.Name))
    {
        var bad = req.CreateResponse(HttpStatusCode.BadRequest);
        await bad.WriteStringAsync("Name is required");
        return bad;
    }

    // ... save to database
    var ok = req.CreateResponse(HttpStatusCode.Created);
    await ok.WriteAsJsonAsync(new { id = Guid.NewGuid(), name = body.Name });
    return ok;
}

public record CreateProductRequest(string Name, decimal Price);

Other Triggers

C#
// Timer trigger — runs on a cron schedule
[Function("DailyReport")]
public void DailyReport([TimerTrigger("0 0 8 * * *")] TimerInfo timer)
    => logger.LogInformation("Daily report triggered at {Time}", DateTime.UtcNow);

// Queue trigger — processes Azure Storage Queue messages
[Function("ProcessOrder")]
public void ProcessOrder(
    [QueueTrigger("orders-queue", Connection = "StorageConnection")] string message)
{
    var order = JsonSerializer.Deserialize<Order>(message);
    logger.LogInformation("Processing order {OrderId}", order!.Id);
}

// Blob trigger — fires when a file is uploaded to blob storage
[Function("ResizeImage")]
public void ResizeImage(
    [BlobTrigger("images/{name}", Connection = "StorageConnection")] byte[] image,
    string name)
    => logger.LogInformation("New image uploaded: {Name} ({Bytes} bytes)", name, image.Length);

Dependency Injection

C#
// Program.cs — isolated worker host
var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults()
    .ConfigureServices(services =>
    {
        services.AddScoped<IProductService, ProductService>();
        services.AddDbContext<AppDbContext>(options =>
            options.UseSqlServer(Environment.GetEnvironmentVariable("DbConnection")));
    })
    .Build();

await host.RunAsync();

Local Settings

JSON
// local.settings.json — never commit this file
{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
    "DbConnection": "Server=localhost;Database=MyDb;..."
  }
}

In Azure, configure these as Application Settings (equivalent of environment variables). Use Key Vault references for secrets:

DbConnection = @Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/DbConnection)

Deploy to Azure

Bash
# Create the function app in Azure (one time)
az group create --name my-rg --location northeurope
az storage account create --name mystorageacct --resource-group my-rg --sku Standard_LRS
az functionapp create \
  --name my-function-app \
  --resource-group my-rg \
  --storage-account mystorageacct \
  --consumption-plan-location northeurope \
  --runtime dotnet-isolated \
  --runtime-version 8

# Deploy
func azure functionapp publish my-function-app

Pricing (Consumption Plan)

First 1 million executions per month: FREE
After that:                          $0.20 per million executions
Execution time:                      $0.000016 per GB-second
Memory:                              128 MB to 1.5 GB configurable
Cold start:                          ~1-3 seconds (mitigated by Premium plan)

When to Use Azure Functions

āœ“ Event-driven processing: image resizing, queue workers, webhooks
āœ“ Scheduled tasks: nightly jobs, cleanup, reports
āœ“ Lightweight APIs with unpredictable traffic
āœ“ Glue code between services
āœ— Long-running work (> 10 minutes on Consumption plan)
āœ— Stateful workflows (use Durable Functions instead)
āœ— High-throughput APIs where cold start latency matters

Key Takeaways

  1. Azure Functions are event-driven — HTTP, timer, queue, blob, and many more triggers
  2. The isolated worker model gives full .NET 8 support with proper DI
  3. Use local.settings.json locally and Application Settings in Azure
  4. Secrets go in Key Vault — never in code or settings files
  5. The Consumption plan has generous free tiers — ideal for low-to-medium workloads

Enjoyed this article?

Explore the learning path for more.

Found this helpful?

Share:š•

Leave a comment

Have a question, correction, or just found this helpful? Leave a note below.