Azure Deploy Example - C# .NET

post-thumb

Today we’ll deploy a tiny C# .NET function to Azure Functions on the Linux Consumption plan. It’s a single HTTP endpoint that returns “Hello world.”

Architecture

LayerComponentResponsibilityFiles / PackagesNotes
ClientCLI (curl) / Postman / HTTPieSend HTTP requests to test the APIUse curl in examples; GUI tools like Postman also work.
API (Functions)Azure Functions (HTTP trigger, isolated)Expose REST endpoints under /api (e.g., /api/test)Functions/Test.cs (or Test.cs), Microsoft.Azure.Functions.WorkerAzure Functions v4 on Linux Consumption, .NET 8 isolated model.
Handler[Function("Test")] methodHandle GET and return JSONFunctions/Test.cs (or Test.cs)Route Route = "test" → final path /api/test; AuthorizationLevel.Anonymous for quick tests.
DTO / PayloadSimple C# object { message: string }Define response shapeInline anonymous type or small record/classKeep payloads explicit; expand to request DTOs as you add POST/PUT later.
Response HelpersWriteAsJsonAsync(...)Consistent JSON responses + content typeMicrosoft.Azure.Functions.Worker.HttpPrefer async APIs (no sync writes).
Error HandlingTry/catch + ctx.GetLogger().LogError(...)Return proper HTTP status codes on failuresFunctions/Test.csReturn 500 on unhandled errors; log via the Functions logger.
ConfigHost + local settingsRuntime & local dev configurationhost.json, local.settings.json/api prefix comes from Functions defaults; secrets in Azure App Settings in the portal.
Build Tooling.NET SDK + Func Core ToolsBuild, run locally, publish to Azure.csproj, dotnet, Azure Functions Core Tools (func)dotnet buildfunc start; func azure functionapp publish <app>.
Cloud ResourcesFunction App + Storage AccountHost the function; triggers/state/checkpointsCreated via az functionapp create, az storage account createStorage account name: 3–24 chars, lowercase + digits, globally unique.
ObservabilityApp Insights (optional)Centralized logs/metrics/tracesEnable in Function App → Application InsightsSuper handy once you add more routes or diagnose issues.
Security/AuthAnonymous (demo)Public endpoint for learningAuthorizationLevel.AnonymousFor real use, switch to Function/Admin or enable Entra ID (Easy Auth).
Platform.NET 8 (isolated worker)Language/runtime version--runtime dotnet-isolated, --runtime-version 8Stick to LTS for stability and Functions compatibility.

Dependencies

If you use VSCode, you may want following extensions:

  • C# (ms-dotnettools.csharp) or C# Dev Kit (ms-dotnettools.csdevkit)
  • Azure Functions (ms-azuretools.vscode-azurefunctions)
  • For Azure sign-in: Azure Account (ms-vscode.azure-account)

Login to Azure and select subscription

We need to login to Azure. Use the default subscription that was created when free account was created.

az login
az account list -o table
az account set --subscription "<Your-Subscription-Name-or-ID>"

Register namespaces

We need a couple namespaces enabled for the application, so enable them if not already. If state is “registering”, wait a couple minutes and run show command again.

az provider show --namespace Microsoft.Storage --query "registrationState"
az provider show --namespace Microsoft.Web    --query "registrationState"
az provider register --namespace Microsoft.Storage
az provider register --namespace Microsoft.Web

Create resource group

Resource group contains all the resources for this project. Choose the location from given list, we use westeurope as an example.

az account list-locations --query "[].name" -o tsv
az group create \
  -n azure-deploy-example \
  -l westeurope

Create storage account

Functions requires a general-purpose storage account for triggers, logs, and state.

Use Standard_LRS (lowest cost). Storage isn’t “free”, but with small usage and free credits it’s typically zero cost while learning. Naming rules: 3–24 chars, lowercase letters & numbers only, globally unique. So in case the name is taken, choose some other name.

az storage account create \
  -n azuredeployecxzxghr0m \
  -g azure-deploy-example \
  -l westeurope \
  --sku Standard_LRS

Create function app

Next we create function application that holds our functions. Application name must be globally unique (becomes <name>.azurewebsites.net).

az functionapp create \
  -n azure-deploy-example-dotnet-ecxzxghr0m \
  -g azure-deploy-example \
  --consumption-plan-location westeurope \
  --runtime dotnet-isolated \
  --runtime-version 8 \
  --functions-version 4 \
  --os-type linux \
  --storage-account azuredeployecxzxghr0m

Prepare the app

The application is very basic, mostly whatever is coming from scaffold. Application sources are here.

Scaffold the project

Create repository files with func cli tool. We use isolated dotnet, so the process dependencies does not get mixed up.

mkdir dotnet-func && cd dotnet-func
func init . --dotnet-isolated

Create function

Save file to Functions/test.ts

using System.Net;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;

namespace Company.Function;

public class Test
{
    [Function("Test")]
    public async Task<HttpResponseData> Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "test")]
        HttpRequestData req,
        FunctionContext ctx)
    {
        var res = req.CreateResponse(HttpStatusCode.OK);
        await res.WriteAsJsonAsync(new { message = "Hello world from dotnet" });
        return res;
    }
}

Note: we use async + WriteAsJsonAsync to avoid the “Synchronous operations are disallowed” error

Run locally

Build and run application, and then we can test it with curl, browser or any other similar tool.

dotnet build
func start

# in another terminal window
curl http://localhost:7071/api/test

Publish

This will publish app to production.

dotnet build
func azure functionapp publish azure-deploy-example-ecxzxghr0m

# test in the cloud
curl https://azure-deploy-example-ecxzxghr0m.azurewebsites.net/api/test

Recap

We created a Function App, added a C# .NET HTTP function, tested locally, and published to Azure.

comments powered by Disqus