Walk-through creating first azure function with dotnet
Heard a lot, but haven ’t used before. First impression - quite handy. In-fact I know some large fintek’s that are using serverless azure functions fore core functionality of a platform. Starting .NET 6 the cold start is close to python (eg. minimal) and scalability is not a question at all.
I gave it a try, and writing down the things I had to google. Will be glad if it will help to save your time.
In case of any issues refer to git repository of this example.
Things you’ll need
I’d assume .NET SKD and ASPNET runtime are installed.
- Azure CLI
- Azure Functions Core Tools
- Code editor of a choice (Rider, VSCode, Visual Studio, etc.)
For Arch uses things are simple yay azure-cli
and yay azure-functions-core-tools-bin
.
For other distros, Windows and macOS click on a links above for detailed instructions.
Creating Function Project
After things were installed, there should be a func
command available in terminal
(at this moment I have version 4.0.4736 installed).
$ func --version
4.0.4736
Create project directory (in my case AzureHelloFn), navigate to it and run func init
.
It will ask you about runtime and language, like on the example below.
For this example I’m choosing dotnet and C#
$ mkdir AzureHelloFn
$ cd AzureHelloFn
$ func initSelect a number for worker runtime:
1. dotnet2. dotnet (isolated process)
3. node
4. python
5. powershell
6. custom
Choose option: 1
dotnet
Select a number for language:
1. c#2. f#
Choose option: 1
c#
Writing /home/den/Projects/samples/AzureHelloFn/.vscode/extensions.json
To avoid questions you can use
--dotnet
option. Eg.func init --dotnet
.
The project is created. You can open it with editor of your choice.
However so far it’s blank. It has only csproj
and some metadata files.
To add a function run func new
(obviously in a project directory)
$ func newSelect a number for template:
1. QueueTrigger
2. HttpTrigger3. BlobTrigger
4. TimerTrigger
5. KafkaTrigger
6. KafkaOutput
7. DurableFunctionsOrchestration
8. SendGrid
9. EventHubTrigger
10. ServiceBusQueueTrigger
11. ServiceBusTopicTrigger
12. EventGridTrigger
13. CosmosDBTrigger
14. IotHubTrigger
Choose option: 2
Function name: HttpHello
HttpHello
The function "HttpHello" was created successfully from the "HttpTrigger" template.
The function is now created. Might seem a bit overcomplicated for start, but is quite self-explanatory.
For the sake of simplicity, let’s also change the
AuthorizationLevel
toAnonymous
on line 16
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace AzureHelloFn;
public static class HttpHello
{
[FunctionName("HttpHello")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, 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;
string responseMessage = string.IsNullOrEmpty(name)
? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
: $"Hello, {name}. This HTTP triggered function executed successfully.";
return new OkObjectResult(responseMessage);
}
}
To run function, just run func start
.
In output, you’ll see local http address where to access the function.
$ func start
...
Functions:
HttpHello: [GET,POST] http://localhost:7071/api/HttpHello
With following plugins Azure Toolkit for Rider and Azure Functions for VSCode, you should also be able to run project from IDE, as well as add new functions without command line. I believe Visual Studio have some support as well.
Paths and api prefix
The path name for function is specified in FunctionName
attribute. The name is NOT CASE-SENSITIVE.
The supported HTTP VERBs are defined in HttpTrigger
attribute (in this case “get”, “post”).
Somehow at the moment function names don’t support slash (/). In other words you cannot name function like
users/get
You may also notice that by default path(s) has api
prefix.
This one can be modified or removed in host.json
you can find in the root folder.
The example below removes prefix.
{
"version": "2.0",
"extensions": { "http": { "routePrefix": "" } }, "logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
}
}
Dependency Injection
So far looks good, but can’t make it far without DI.
For example we want to remove message compose logic from http function to a dedicated service MessageService
.
// MessageService.cs
namespace AzureHelloFn;
public class MessageService
{
public string ComposeMessage(string name) =>
string.IsNullOrEmpty(name)
? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
: $"Hello, {name}. This HTTP triggered function executed successfully.";
}
To configure DI we’ll need
Microsoft.Azure.Functions.Extensions
package.
$ dotnet add package Microsoft.Azure.Functions.Extensions
To register service, let’s add Startup
class that must inherit FunctionsStartup
// Startup.cs
using Microsoft.Azure.Functions.Extensions.DependencyInjection;using Microsoft.Extensions.DependencyInjection;
namespace AzureHelloFn;
public class Startup: FunctionsStartup{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddSingleton<MessageService>(); }
}
The next thing to do , is to tell azure functions to use StartupClass
we defined.
Therefore, let’s add Assembly.cs
with following code.
using AzureHelloFn;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
[assembly: FunctionsStartup(typeof(Startup))]
As you may see, the names are not conventional. You can use whatever class name for Startup
,
as well as you can add FunctionStartup
assembly attribute anywhere you wish (out of namespace)
this is how you actually specify which class will be used at start up.
Finally, let’s update our function to use MessageService
.
To do so, remove static marker from class itself and method.
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace AzureHelloFn;
public class HttpHello{
readonly MessageService _messageService;
public HttpHello(MessageService messageService) => _messageService = messageService;
[FunctionName("HttpHello")]
public async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
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;
return new OkObjectResult(_messageService.ComposeMessage(name)); }
}
Use func start
or some fancy IDE feature to run the function.
The behaviour shouldn’t have changed.
Deploy to azure
Deploy is even easier, all you need is to run func azure functionapp publish <FUNCTION-APP-NAME>
,
however function app must be created.
Below will be instructions how to create function app using Azure CLI, be if you prefer clicking,
below will be gui instructions for clickers.
In this example I’ll be creating resource group
playground
azure storage accountdennisplaygroundstorage
and function appAzureHelloFn
The names for storage account and function app MUST BE GLOALLY UNIQUE, therefore you’ll need to come up with your own names!
Creating Azure function app
You can check if you are logged in using az account show
command.
If you are not, use az login
command and follow instructions.
$ az login
Below will be instructions how to create Function App and necessary resources using command line, but you can do it using Azure Portal as well.
Next we’ll create a resource group.
If you already have a resource group created, you can skip it,
otherwise use the command below with RESOURCEGROUPNAME
of your choice.
You can refer to List of azure region names
choosing region.
$ az group create --name <RESOURCEGROUPNAME> --location <REGION>
Next, creating storage account.
Once again if you already have a storage account you with to use you can skip it,
Otherwise use the command below giving it an existing resource group name and STORAGEACCOUNTNAME
of your choice (alfa-numeric, staring with letter).
You can refer to Azure SKU types
if you want to choose SKU other than Standard_LRS
give on example.
$ az storage account create --name <STORAGEACCOUNTNAME> --location <REGION> --resource-group <RESOURCEGROUPNAME> --sku Standard_LRS
Finally, creating function app.
You’ll need also to specify --os-type
which can be windows
or linux
, when not specified defaults to windows
.
You will also need to give it a functions version, to check the version of your SDK you can run func --version
(use major version, eg. first number).
$ az functionapp create --resource-group <RESOURCEGROUPNAME> \
--storage-account <STORAGEACCOUNTNAME> \
--consumption-plan-location <REGION> \
--os-type <windows|linux> \
--runtime dotnet \
--functions-version 4 \
--name <FUNCTIONAPPNAME>
Be patient, it might take a while.
Publishing Azure Function
Assuming you are already logged-in in Azure CLI,
you can test it using az account show
command and if not
login using az login
command.
In the root directory of a project, just run $ func azure functionapp publish <FUNCTIONAPPNAME>
like on example below.
In the output it will also print http endpoint where the function can be accessed.
In my example the function app name was azurehellofn
.
$ func azure functionapp publish <FUNCTIONAPPNAME>
...
Functions in AzureHelloFn:
HttpHello - [httpTrigger]
Invoke url: https://azurehellofn.azurewebsites.net/httphello
That’s it happy coding :)
Useful resources
In case of any issues compare your code with my git repository for this example.
- Instructions to install Azure CLI
and Azure Functions Core Tools,
on Arch simply
yay azure-cli
andyay azure-functions-core-tools-bin
. - Plugins Azure Toolkit for Rider and Azure Functions for VSCode.
- List of azure region names
- Azure SKU types for storage.