Skip to main content
rule official · GitHub

azure-functions-csharp — GitHub Copilot rule: Azure Functions in C#

A GitHub Copilot rule that sets conventions for building Azure Functions in C# with the isolated worker model. Useful when you want consistent style across a functions project.

Install into GitHub Copilot · Manually: put the files in place All methods and platforms ↓
.github/instructions/azure-functions-csharp.instructions.md
Open on GitHub

What azure-functions-csharp does

The rule covers how to build Azure Functions in C# using the isolated worker model instead of the legacy in-process one. It calls for host setup via FunctionsApplication.CreateBuilder(args) or HostBuilder in Program.cs, [Function("FunctionName")] on methods, and business logic pushed into DI-registered services. Logging goes through constructor-injected ILogger<T>, and all I/O uses async/await.

Separate sections handle triggers and bindings. For HttpTrigger it recommends AuthorizationLevel.Function or higher in production; for TimerTrigger, NCRONTAB expressions and no RunOnStartup = true. Blob triggers should use Event Grid rather than polling. Secrets come from IConfiguration or environment variables, and deployed environments use Key Vault references with Managed Identity.

The rule applies to **/*.cs, **/host.json, **/local.settings.json and **/*.csproj. It assumes the Microsoft.Azure.Functions.Worker packages and their extensions, so on a project without those dependencies the suggestions will miss. For resilience it points to Polly v8 or Microsoft.Extensions.Http.Resilience; for observability, Application Insights and ActivitySource.

What it helps with

  • pick the isolated worker model over in-process for a new project
  • set up DI and the host in Program.cs without logic inside functions
  • choose an authorization level for a production HTTP trigger
  • drop polling on a blob trigger in favour of Event Grid
  • configure retry policies and dead-lettering for queues

Example prompts for the agent

  • Check my Program.cs against the azure-functions-csharp rules
  • Rewrite this HttpTrigger for the isolated worker model
  • Set up host.json for QueueTrigger with retries and dead-lettering

How to install azure-functions-csharp

Manually: put the files in place

.github/instructions/azure-functions-csharp.instructions.md

The applyTo field sets which files it applies to

Step by step, with commands for each platform: AGENTS.md vs CLAUDE.md: what they are and which one to use

Questions about azure-functions-csharp

How do I install azure-functions-csharp in GitHub Copilot?

Copy the rule file to .github/instructions/azure-functions-csharp.instructions.md in your repository root. GitHub Copilot picks it up for the files listed in applyTo.

What does azure-functions-csharp do?

It gives GitHub Copilot a set of guidelines for Azure Functions in C#: isolated worker model, DI, triggers, bindings, error handling and logging.

Which files does this rule apply to?

**/*.cs, **/host.json, **/local.settings.json and **/*.csproj — that is what the applyTo field lists.

Source text

azure-functions-csharp.instructions.md · MIT
---
description: 'Guidelines and best practices for building Azure Functions in C# using the isolated worker model'
applyTo: '**/*.cs, **/host.json, **/local.settings.json, **/*.csproj'
---

# Azure Functions C# Development

## General Instructions

- Always use the **isolated worker model** (not the legacy in-process model) for all new Azure Functions projects targeting .NET 6 or later.
- Use `FunctionsApplication.CreateBuilder(args)` or `HostBuilder` in `Program.cs` for host setup and dependency injection.
- Decorate function methods with `[Function("FunctionName")]` and use strongly typed trigger and binding attributes.
- Keep function methods focused — each function should do one thing and delegate business logic to injected services.
- Never put business logic directly inside the function method body; extract it into testable service classes registered via DI.
- Use `ILogger<T>` injected through the constructor, not `ILogger` passed as a function parameter, for consistent structured logging.
- Always use `async/await` for all I/O-bound operations; never block with `.Result` or `.Wait()`.
- Prefer `CancellationToken` parameters where supported to enable graceful shutdown.

## Project Structure and Setup

- Use the `Microsoft.Azure.Functions.Worker` and `Microsoft.Azure.Functions.Worker.Extensions.*` NuGet packages.
- Register services in `Program.cs` using `builder.Services.Add*` extension methods for clean dependency injection.
- Group related functions into separate classes by domain concern, not by trigger type.
- Store configuration in `local.settings.json` for local development; use Azure App Configuration or Application Settings for deployed environments.
- Never hardcode connection strings or secrets in code; always read from `IConfiguration` or environment variables.
- Use Key Vault references (`@Microsoft.KeyVault(SecretUri=...)`) in App Settings for secrets in deployed environments.
- Use `Managed Identity` (`DefaultAzureCredential`) for authenticating to Azure services — avoid connection strings with keys wherever possible.
- Keep `host.json` tuned per trigger type: configure `maxConcurrentCalls`, `batchSize`, and retry policies at the host level.

## Triggers

- **HttpTrigger**: Use `AuthorizationLevel.Function` or higher for production endpoints; reserve `AuthorizationLevel.Anonymous` only for public-facing APIs with explicit justification. Use ASP.NET Core integration (`UseMiddleware`, `IActionResult` returns) when using the ASP.NET Core integration model.
- **TimerTrigger**: Use NCRONTAB expressions (`"0 */5 * * * *"`) for schedules; avoid `RunOnStartup = true` in production as it executes immediately on every cold start.
- **QueueTrigger / ServiceBusTrigger**: Configure `MaxConcurrentCalls`, dead-letter policies, and `MaxDeliveryCount` in `host.json` and Azure portal; handle `ServiceBusReceivedMessage` directly for advanced message control (complete, abandon, dead-letter).
- **BlobTrigger**: Prefer Event Grid-based blob triggers (`Microsoft.Azure.Functions.Worker.Extensions.EventGrid`) over polling-based blob triggers for lower latency and reduced storage transaction costs.
- **EventHubTrigger**: Set `cardinality` to `many` for batch processing; use `EventData[]` or `string[]` parameter types for batch mode; always checkpoint using the `EventHubTriggerAttribute`'s built-in checkpointing.
- **CosmosDBTrigger**: Use the change feed trigger for event-driven processing of Cosmos DB changes; set `LeaseContainerName` and manage lease containers separately from data containers.

## Input and Output Bindings

- Use input bindings to read data declaratively rather than using SDKs directly inside function bodies where the binding covers the use case.
- For multiple output bindings, define a custom return type with properties annotated with the appropriate output binding attributes (e.g., `[QueueOutput]`, `[BlobOutput]`, `[HttpResult]`).
- Use `[BlobInput]` and `[BlobOutput]` for blob read/write; prefer `Stream` over `byte[]` for large blobs to avoid memory pressure.
- Use `[CosmosDBInput]` for point reads and simple queries; for complex queries, inject `CosmosClient` via DI with `Managed Identity`.
- Use `[ServiceBusOutput]` for single-message sends; inject `ServiceBusSender` via DI for batching or advanced send scenarios.
- Avoid mixing SDK clients obtained via DI with binding-based I/O for the same resource — choose one pattern per resource to maintain consistency.

## Dependency Injection and Configuration

- Register all external clients (e.g., `BlobServiceClient`, `ServiceBusClient`, `CosmosClient`) as singletons using `services.AddAzureClients()` from the `Azure.Extensions.AspNetCore.Configuration.Secrets` package with `DefaultAzureCredential`.
- Use `IOptions<T>` or `IOptionsMonitor<T>` for strongly typed configuration sections.
- Avoid using `static` state in functions; all shared state should flow through DI-registered services.
- Register `HttpClient` instances via `IHttpClientFactory` to manage connection pooling and avoid socket exhaustion.

## Error Handling and Retry

- Configure built-in retry policies in `host.json` using `"retry"` with `fixedDelay` or `exponentialBackoff` strategy for trigger-level retries.
- For transient fault handling at the code level, use `Microsoft.Extensions.Http.Resilience` or Polly v8 (`ResiliencePipeline`) with retry, circuit breaker, and timeout strategies.
- Always catch specific exceptions and log them with structured context (e.g., correlation ID, input identifier) before re-throwing or dead-lettering.
- Use dead-letter queues for messages that fail after all retries; never silently swallow exceptions in function handlers.
- For HTTP triggers, return appropriate `IActionResult` types (`BadRequestObjectResult`, `NotFoundObjectResult`) rather than throwing exceptions for expected error conditions.

## Observability and Logging

- Use `ILogger<T>` with structured log properties: `_logger.LogInformation("Processing message {MessageId}", messageId)`.
- Configure Application Insights via `builder.Services.AddApplicationInsightsTelemetryWorkerService()` and `builder.Logging.AddApplicationInsights()` in `Program.cs`.
- Use `TelemetryClient` for custom events, metrics, and dependency tracking beyond what is automatically collected.
- Set appropriate log levels in `host.json` under `"logging"` to avoid excessive telemetry costs in production.
- Use `Activity` and `ActivitySource` from `System.Diagnostics` for distributed tracing context propagation between functions and downstream services.
- Avoid logging sensitive data (PII, secrets, connection strings) in any log statement.

## Performance and Scalability

- Keep function startup time minimal: defer expensive initialization to lazy-loaded singletons, not the function constructor.
- Use the Consumption plan for event-driven, unpredictable workloads; use Premium or Dedicated plans for low-latency, high-throughput, or VNet-integrated scenarios.
- For CPU-intensive work, offload to a background `Task` or use Durable Functions rather than blocking the function host thread.
- Batch operations where possible: process `IEnumerable<EventData>` or `ServiceBusReceivedMessage[]` arrays in a single function invocation rather than one message at a time.
- Set `FUNCTIONS_WORKER_PROCESS_COUNT` and `maxConcurrentCalls` appropriately for the hosting plan and expected throughput.
- Enable `WEBSITE_RUN_FROM_PACKAGE=1` in App Settings for faster cold starts by running directly from a deployment package.

## Security

- Always validate and sanitize HTTP trigger inputs before processing; use FluentValidation or Data Annotations.
- Use `AuthorizationLevel.Function` with function keys stored in Key Vault for internal API-to-API calls.
- Integrate Azure API Management (APIM) in front of HTTP-triggered functions for public-facing APIs to handle auth, rate limiting, and routing.
- Restrict inbound access using App Service networking features (IP restrictions, Private Endpoints) for sensitive functions.
- Never log request bodies containing PII or secrets.

## Testing

- Unit-test service classes independently of the function host using standard xUnit/NUnit with mocked dependencies.
- Integration-test functions using `Azurite` (local Azure Storage emulator) and `TestServer` or the Azure Functions Core Tools.
- Use the `Microsoft.Azure.Functions.Worker.Testing` helpers where available to construct mock `FunctionContext` instances.
- Avoid testing the trigger plumbing itself; focus tests on the business logic extracted into services.

## Existing Code Review Guidance

- If a project uses the legacy **in-process model** (`FunctionsStartup`, `IWebJobsStartup`), suggest migrating to the isolated worker model and provide the migration path via `dotnet-isolated-process-guide`.
- If hardcoded connection strings or storage account keys are found in code or config files, flag them and suggest replacing with `DefaultAzureCredential` and Key Vault references.
- If `RunOnStartup = true` is set on a `TimerTrigger` in a production app, flag it as a risk and suggest using deployment slots or feature flags instead.
- If `async void` is used in any function, flag it immediately — use `async Task` instead.
- If retry logic is implemented manually with `Thread.Sleep` or `Task.Delay` inside a function, suggest replacing with host-level retry policies or Polly resilience pipelines.

© github · MIT · github/awesome-copilot

Similar IDE rules

All IDE rules for Cloud: AWS, Azure, GCP →

From the same set732

The whole set →
azure-naming The rule makes GitHub Copilot name Azure resources following Microsoft CAF: type prefix, workload, environment, region, instance number. ★ 40,418repo stars azure-logic-apps-power-automate A GitHub Copilot rule that guides JSON workflow definitions for Azure Logic Apps and Power Automate: triggers, actions, error handling. ★ 40,418repo stars azure-iot-edge-architecture Requires reviewing Azure IoT Edge documentation before proposing architectures. It targets Bicep, Terraform, and edge-related markdown files. ★ 40,418repo stars azure-functions-typescript This rule guides Copilot when generating TypeScript APIs for Azure Functions, including async code and endpoint file layout. It also calls for updating the OpenAPI schema and README.md when the API changes. ★ 40,418repo stars azure-durable-functions-csharp Sets guidelines for building C# Azure Durable Functions in the isolated worker model. Enforces replay safety, correct logging, and task hub configuration. ★ 40,418repo stars azure-devops-pipelines This rule guides Azure DevOps Pipeline YAML structure, testing, security, and deployment. Use it when reviewing or maintaining pipeline files. ★ 40,418repo stars aws-appsync Guides GitHub Copilot to write AWS AppSync Event API handlers using the constrained APPSYNC_JS runtime, official utilities, and strict data source patterns. ★ 40,418repo stars attester-verify-packages Checks PyPI and npm package and symbol names through attester.dev before installation or import. It helps keep invented dependencies out of code. ★ 40,418repo stars

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor