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.
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
# 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 anonymousThe --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
// 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:
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 returnReading the Request Body
[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
// 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
// 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
// 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
# 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-appPricing (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 mattersKey Takeaways
- Azure Functions are event-driven ā HTTP, timer, queue, blob, and many more triggers
- The isolated worker model gives full .NET 8 support with proper DI
- Use
local.settings.jsonlocally and Application Settings in Azure - Secrets go in Key Vault ā never in code or settings files
- The Consumption plan has generous free tiers ā ideal for low-to-medium workloads
Found this helpful?
Leave a comment
Have a question, correction, or just found this helpful? Leave a note below.