Skip to main content

Azure Functions Fundamentals

Hello friends! In this blog I am going to talk about fundamentals of Azure Functions. 

Azure Functions is a server less solution that allows you to write less code, maintain less infrastructure, and save on costs. Instead of worrying about deploying and maintaining servers, the cloud infrastructure provides all the up-to-date resources needed to keep your applications running.


Hence, main advantages of Azure Functions are - 

  • serverless programming
  • highly scalable
  • low cost


Azure Functions can be look on as Events + Code which means all we have to do is to write code and then tell Azure what trigger will run the code. A trigger can be a scheduler, a message in MessageQueue, a new item in blob storage, a http request etc.

So how do we run code in Azure -

Azure VM

install whatever u want

web servers, windows services etc

IaaS

complete control of the serverless

choose your operating system

You are responsible

patching and maintaining

scaling

operational overhead

Azure app services

PaaS

Azure web applications

easy to deploy

choice of many frameworks

Hosting in a hosting plan

combine multiple sites on one server

scale up to many servers

Web jobs -simple way to keep running background jobs in webapplications

simplified background tasks

the basis for azure functions

Azure functions is based on webjob hosted on web app services


Azure functions are part of App services. It can be seen as a simplified programming tool which helps to 

  • just write the code to respond to the event
  • eliminate the boilerplate
  • focus on business requirements

It has consumption based pricing model - 

  • pay as you go
  • only pay for what you use
  • automatic scale

Azure functions pricing

run in app service plan

you can use existing pricing models

pay for dedicated servers

predictable monthly costs

serveral prciing tiers

or use the consumption based pricing model

Billing

number of executions

cpu time*Ram

free monthly grant available

Cutting costs

reduces your costs with

faster invocation times

fewer invocations

reduced memory requirements

consumption plan

optional daily quota

limited to five mins per executions

Docker Container

azure function can be run in docker containers

host anywhere

onprem

other cloud providers


Benefits of Azure Functions

  • Rapid and simple development

code within azure portal

eliminate boilerplate

  • All the powers of azure web apps

ci, kudu, easyauth, certificates, custom domains, settings etc

  • Cost effective pricing

pay for what you use

  • No servers to maintain

automatic scaling



What is SERVERLESS ARCHITECTURE?

There are still servers of course even in a serverless architecture.

you delegate the management of the server

use PaaS wherever possible

e.g comos db, auth0

run your custom code on azure functions

respond to events

Functions as a service (FaaS)

A real world example

monolithic architecture is hard to scale and tries to do everything

Refractoring to functions

payment provider as azure function which places a message in queue

this triggers generate license message which is azure func which stores license file in blob storage

this triggers license file azure func which sends email to customer

report error web hook azure func which add new row in table storage

validate license api azure func which does a db lookup

nightly scheduled task azure func generated report eachnight

Our web server now has lot less to do

Microservices taken to next level


Function app - group related functions together

e.g. previous examples all funcs can be grouped in single func app


Azure functions use cases

experiments and prototyping

automating development processes

integrate slack with CI server

decomposing or extending monolithic applications

independent scaling

adapters for integrating systems

go serverless


CREATING YOUR FIRST AZURE Function

Demo - 

open tryfunctions.com>

scenario - webhook+api, timer, data processing

>langugae - c#, java

>Create function>creates function in AZURE

Function app has a randomly generated name

httptiggerCSharp1 contains run.csx contains code for the function which gets triggered 

function.json - defines each func in azure function

viewfiles tab shows code files

test tab provides option to trigger func and check output

logs window show the logs

Get function url - url for the func


Creating functions from templates

lang - JS

plus button helps to add a function 

one can select any function template to create function (just like build templates)

functions select many languages like JS, Powerhsell, typescript, C#

TimeTrigger - runs on schedule


Create a function app in azure portal

Create a resource>Function app>name>subscription>resource group>OS>hostingplan=consumptionPlan>location>runtime stack=.NET>Storage=CreateNew>Create

Function app setting - 

runtime version

daily usage quota

function app edit mode (read/write or read only)

host keys to call the function

Application Settings


The files of azure functions gets stored in storage account e.g. logs, fucntion.json etc.

All the code for azure functions is opensource


UNDERSTANDING TRIGGER AND BINDINGS

Bindings

connect to external resources

reduce amount of code


check standard documentation


Developing Azure Functions

Visual Studio>Azure development (enables all azure tools)

Azure function core tools

cross platform

command line

.NET SDK shall be installed

azure function core tools

install using npm

open powershell

>func

>func init //creates azure fucntion project in the folder

Select a worker runtime:dotnet

host.json

local.settings.json //startup values

open the project in VS code

Demo - webhook trigger

>func new

Select a template:

HttpTrigger

>FunctionName: OnPaymentReceived

the function created successfully.

.cs files get added successfully

WIthin .cs

[FunctionName("OnPaymentReceived")]//attributes 

public static async Task<IActionResult> Run(

[HttpTrigger(AuthorizationLevel.Function, "get",//signifies this is an HttpTrigger

"post", Route=null)]HttpRequest req,

ILogger log){

string requestBody= await new StreamReader (req.Body).ReadToEndAsync();

dynamie data =JsonConvert.DeserializeObject(requestBody);

return new OkObjectResult($"Thanks for your purchase");

}

func start //starts function in cmd line

default route is 

api/functionName?id=123

One can trigger the request the method using Powershell

iwr -Method POST

-Uri http://localhost:7091/api/OnPaymentReceived

-Headers @{"Content-Type"="application/json"}

-Body '{}'

when running locally, function doesnt need the secret code

Compilation of projects will update the bin folder

function.json - details of http trigger

Demo - Queue output binding

we want func to post a message to queue which allows to generate license file async

message sent to azure queue storage (or service bus as well if needed)

nuget pkg to allow storage bindings for sending a message to queue- Microsoft.Azure.WebJobs.Extension.Storage

output binding - to write message to queue

>Add the nuget to project for storage

>add queue binding to func

[FunctionName("OnPaymentReceived")]//attributes 

public static async Task<IActionResult> Run(

[HttpTrigger(AuthorizationLevel.Function, "get",

"post", Route=null)]HttpRequest req,

[Queue("orders", Connection="MyAppSetting")]:IAsyncColletor<Order> orderQueue,

ILogger log){

string requestBody= await new StreamReader (req.Body).ReadToEndAsync();

dynamic order =JsonConvert.DeserializeObject(requestBody);

await orderQueue.AddAsync(order);//connects/creates queues, serialize message and send it

return new OkObjectResult($"Thanks for your purchase");

}

How func knows which queue storage to connect to - If not mentioned, func loooks for default storage for func app. Else mentioned using Connection in Queue attribute

Go to storage account >Accesskeys >get the connectionstring>paste connectionstring to AzureWebJobStorage in local.settings.json

local.settings.json - shall not be placed in source control


Two types of C# function

C# script files (.csx)

C# class library (.dll)


Azure function core tools -

open source cross platform

function templates

allow to create functions easily



BUILDING A FUNCTION PIPELINE

Demo - Listen to a queue

in VS>FIle>New>Azure>Azure Functions to create a function projects

Add a new function - GenerateLicenseFile>Select Queue Trigger template>connectionstring setting>queue name

[FunctionName("GenerateLicenseFile")]

public static void Run(

[QueueTrigger("orders", Connection="AzureWebJobStorage")]Order order,//to listen to the queue

[Blob("licenses/{rand-guid}.lic")] TextWriter outputBlob,//To add binding to write license file to blob stroage , if blob container not present , it gets created

ILogger log)

{

outputBlob.WriteLine($"OrdereId:{order.orderId}");

.

.

.

var md5 = System.Security.Cryptography.MD5.Create();

var hash = md5.ComputeHash(

System.Text.Encoding.UTF8.GetBytes(order.Email+"secret"));

outputBlob.WriteLine($"SecretCode"{BitConverter.ToString(hash).Replace("-","")}"

}


Besides text, we can write stream, byte, string etc. to blob (check documentation)

{rand-guid} - special syntax to genernate random guid

orders - name of the blob storage, it not present it will be created

Demo -Blob trigger to send email to customer

Create a new func - EmailLicenseFile>Blob trigger template>ConnectionString=AzureWebJobStorage>Path=licenses (where we look for new blobs)

[FunctionName("EmailLicenseFile")]

public static void Run(

[BlobTrigger("licenses/{name}", 

Connection="AzureWebJobStorage")]string licenseFileContents,//to listen to the blob entries

[SendGrid(ApiKey="SendGridApiKey")] out SendGridMessage message, //out used as the func is not aysnc. In that case we use IAsyncCollector 

//api key comes from local.settings.json

string name,//gets mapped to {name} from blobtrigger

ILogger log)

{

var email = Regex.Match(input:licenseFileContents,

pattern:@"^Email\:\ (.+)$", RegexOptions.Multiline).Groups[1].Value;

messgae = new SendGridMessage();

message.From= new EmailAddress(Environment.GetEnvironmentVariable("EmailSender"));

message.AddTo(email);

var plaintTextBytes = System.text.Encoding.UTF8.GetBytes(licenseFileContents);

var base64 = Convert.Tose64String(plainTextBytes);

message.AddAttachment(filename:name, content:base64, type:"text/plain");

message.Subject...

}

Get Microsoft.AZURE.WebJobs.Extensions.SendGrid - 3rd party binding available to send emails

Input the blob trigger func can be string, stream, TextReader, byte[], ICLoudBlob etc.


You can always write your code if some binding are not available

Bindings are provided for convenience


Demo - Table Storage Output

Output Bindings 

Azure Cosmos db

azure table storage 

no binding for azure sql. SO write custom code or use EF


So, we will update the OnPaymentReceived func to add a row to table by adding another binding 


[FunctionName("OnPaymentReceived")]//attributes 

public static async Task<IActionResult> Run(

[HttpTrigger(AuthorizationLevel.Function, "get",

"post", Route=null)]HttpRequest req,

[Queue("orders", Connection="MyAppSetting")]:IAsyncColletor<Order> orderQueue,

[Table("orders")IAsyncCollector<Order> orderTable,

ILogger log){

string requestBody= await new StreamReader (req.Body).ReadToEndAsync();

dynamic order =JsonConvert.DeserializeObject(requestBody);

await orderQueue.AddAsync(order);//connects/creates queues, serialize message and send it

order.PartitionKey="orders";//jsut one partition for demo purpose

order.RowKey = order.OrderId;

await orderTable.AddAsync(order);

return new OkObjectResult($"Thanks for your purchase");

}

Table storage uses additional elements. Hence we need to update them.

public class Order{

public string PartitionKey{}

public string RowKey {}

.

.

.

}

Demo - IBinder and Table Storage

-IBinder:Contorl license filename

InputBinding 

Lookup order in Azure Table Storage

Optional Email sending

Case 1 - Set the license file name as the orderid. Since orderId is not available at the time of function definition, we will used IBinder to create Blob binding at runtime to use orderId as the output file name

[FunctionName("GenerateLicenseFile")]

public static async Task Run(

[QueueTrigger("orders", Connection="AzureWebJobStorage")]Order order,//to listen to the queue

//Instead of guid we want to use orderId here,

IBinder binder, //binder will create blobbinding to write to blob storage

ILogger log)

{

//outputBlob is result of binding of textwrite and pssing in a blob attribute that has filename that we want

var outputBlob = await.binder.BindAsync<TextWriter>(

new BlobAttribute($"licenses/{order.Orderid}.lic")

{

Connection="AzureWebJobsStorage"

}

outputBlob.WriteLine($"OrdereId:{order.orderId}");

.

.

.

var md5 = System.Security.Cryptography.MD5.Create();

var hash = md5.ComputeHash(

System.Text.Encoding.UTF8.GetBytes(order.Email+"secret"));

outputBlob.WriteLine($"SecretCode"{BitConverter.ToString(hash).Replace("-","")}"

}

IBinder Interface

customize any binding at runtime

calculate attribute parameters on-demand in functoin body

Case 2 - validate licenseFile by matching with Order.Email in EmailLicenseFile and making email sending optional

[FunctionName("EmailLicenseFile")]

public static void Run(

[BlobTrigger("licenses/{orderId}.lic", //GenerateLicenseFile has added orderid as file name now. So the trigger will work on addition to blob when name is of format {orderId}.lic

Connection="AzureWebJobStorage")]string licenseFileContents,//to listen to the blob entries

[SendGrid(ApiKey="SendGridApiKey")] IColletor SendGridMessage sender, //ICollector same as IAsyncCollector but this is not asyc. This change is done to create a sender 

//api key comes from local.settings.json

[Table("orders"<table name>,"orders"<partitionkey in row>,"{orderId}")]Order order,

string orderId,//gets mapped to {orderId} from blobtrigger

ILogger log)

{

//var email = Regex.Match(input:licenseFileContents,

//pattern:@"^Email\:\ (.+)$", RegexOptions.Multiline).Groups[1].Value;

var email = order.Email;

var messgae = new SendGridMessage();

message.From= new EmailAddress(Environment.GetEnvironmentVariable("EmailSender"));

message.AddTo(email);

var plaintTextBytes = System.text.Encoding.UTF8.GetBytes(licenseFileContents);

var base64 = Convert.Tose64String(plainTextBytes);

message.AddAttachment(filename:orderId, content:base64, type:"text/plain");

message.Subject...

if(!email.EndsWith("@test.com"))//TO MAKE EMAIL SENDING OPTIONAL

sender.Add(message);

}

DEPLOYING AZURE FUNCTIONS

-create the infra >

-app service plan to host function

-storage account

-application insights instance

-function app

using - Azure portal or visual studio

Infra as Code

Azure CLI

ARM templates

Once infra is up, one has to publish function code and set the settings

Manual publishing 

Azure portal

Visual studio

Automated publishing

publish zip with kudu api

run from package - publish zip to storage account and settings tell where to look for code

Git repository

Azure functions core tools 

func azure functionapp

AzureCLI

az functionapp deployment source config-zip

Azure DevOps pipelines 

Cake - addons to publish func apps


Demo - Create func app using AzureCLI

az //helps with subcommands

az functionapp -h //shows all subcommands for functionapp

az login

az account set -h "<subscription name>"

az group create -n $resourceGroup -l $location//create resourceGroup

az sotrage account create -n $stoarageaccount -l $locaiton //create storage account

az resource create -g $resourceGroup -n $appINsights 

--resource-type "Microsoft.Insights/components"

--properties "@props.json" // properties defined in props.json

az functionapp create -n $functionAppName

-g $resourceGroup--storage-account $stoarageaccount

--app-insights $appInsights

.....

az functionapp config appsettings set -n $functionAppName -g $resourceGroup

--setting "MySetting1=Hello" "MySetting2=world" //sets the app settings

Demo - Create func app using ARM template

refer documentation for azure-quickstart-templates

az group crate -n $res -l $locaiton

az group deployment create <paramenters> //create functionapp using ARM

Demo - Create and Publish using VS

Publish>Azure FunctionAPp>Select Existing/Create New

Check Run from package file>Next>select function app (if existing selected)>PUblish

IN APplication Settings>check the values >Insert vale fro Local>

Once published>Functions will start appearing in func app> Get url to test in postman


Demo -

Command line publishing

Azure function core tools

func azure functionapp publish pluralSighFunc2019<name of func app>

pushes zip to function app

zip got uploaded to storage account

its sas uri got stored in appsettings of func app (WEBSITE_RUN_FROM_APP)

Azure CLI

wont create zip package.

so create a zip - dotnet publish -c release

az functionapp deployment source config-zip

-g resourceGroup -n funcname

--src publish.zip

in func apps kudu, Data>SitePackages (packages from VS or AzureCLI)

Demo - Deploying azure func in docker container

core tools can generate file for usage

md dockerfuncs

cd .\dockerfuncs\

func init --docker

slelct worker:dotnet

cat .\DockerFile

we can create a docker image using the docker fiel

func new //create new func

docker version //

docker build -t dockerfuncs:v1//creates an image

u cna run this docker image on any docker host


WORKING IN PRODUCTION

 

HOW TO MONITOR - integrate with application insights

when did my function run

invocation history - 

each func in func app has a monitor tab in blade. It shows the invocation history, log output etc

Run in application insights - link to open the query in AI insance

what did they output in logs

how much am i spending

func app >Platform Features>metrics>fucntion execution count, function execution units used for pricing calculation

func app >metrics>setup alert using Rule>Daily Usage Quota (func stops when limit reached till next day); to save cost

subscription >shows all the costs> click on one of the items on pie chart >

HOW TO SECURE

so that only authorized users trigger the function (especially in httptrigger)

function keys - 

we can choose authorization level bw - anonymous (all), function(secret code for the func in code query string parameter or x-fucntions-key in http trigger) & admin(when one code for all functions;dont want separate keys for different fucntions)

cycle and revoke keys

enable easy auth 

applices to entire func app

integrates with azure ad, google, fb and others

redirects unauthrized users to login page

perform own validation

e.g validate a JWT bearer token

danger!high risk of mistakes

Azure API mgmt

offers many features

proxies traffic to your func app

Demo - How to configure func keys

in Func>Manage>fucntion keys, hostkeys present >

in func > get func url contains options to which kind of url we want (default(function keys))

HOW TO CONFIGURE CORS

calling functions from javascript

func app>platform features>CORS

CORS - which urls are allowed for CORS

HOW TO INTEGRATE WITH OTHER AZURE SERVICES

Proxies

redirect incoming http requests to func app to other apps, SA etc

Demo - 

proxies.json - stores proxies

func app>Proxies>No proxies by default>+ New Proxy>Route template=/>allowed http methods=GET>backend URL = where the url should get proxied to eg. storage account index.html>

request override (optional)>response override(optional)>Create

e.g. func app>proxies>route template=/images/[*restOfPath]>bahckend url = https://server/sdfdsfsdfdsf/images/[restOfPath]

Advanced Editor - shows files that makeup func app>shows proxies.json containing the proxies we created

Key Vault

to store secrets

access with managed identity

Demo -

func app>secrets>

in azure key vault, secrets have secret identifier > copy this identifier

key vault>platform features>identity>Status=On (func app id created in Azure AD)

This id of func app needs to be granted read on key vault

key vault>access policies>new>select principal (created in previous step>Create

func app > application settings>new setting>sendGridAPiKey =@Microsoft.KeyVault(SecretUri=https://my-key-vault.azure.net?secrets?my-seret?343rewfsdgrwrewfdsvsrwrwfsdffgdsg)>Save

Azure Devops Pipelines

automate func app deployment

Azure Event Grid

service that subscribe to events by any azure resource

e.g. deployment completed

API management

api gateway sits in front and add security

cahcing, usage quotas, rate limiting

serverless pricing tier

Demo -

Create a resource for API mgmt Service>

APIs>Add a new API>Select function  app>import azure funcs by seleting ur func app>

Inbound policies>filter ip address>set headers>set response caching etc

Great security features>

Oauth configurable,

OpenId connect

client certificates

HOW TO BUILD WORKFLOWS

chaining of func app to create workflow. But it has following limitations -

how far through we are

how can we handle errors

how can we retry transient failutes

how can we wait for external events

how can we execute steps in paraller

Durable function helps solve it

orchstrator func - defines the steps in your workflow

activity func - implements a step in workflow

Demo - 

public static async Task<IActionResult> Run(

[HttpTrigger(AuthorizationLevel.Function, "get",//signifies this is an HttpTrigger

"post", Route=null)]HttpRequest req,

[OrchestrationClient] DurabelOrchestrationClinet durableCLient,//starts durable workflow

ILogger log){

string requestBody= await new StreamReader (req.Body).ReadToEndAsync();

dynamie data =JsonConvert.DeserializeObject(requestBody);

var orchestrationId = await durableCLient.StartNewAsync(

nameof(NewOrderWorkflow), order);//id used to track the progress

//NewOrderWorkflow will call other activies in workflow e.g. generateLicenseFile, emailLicenseFile etc

var response = durableCLient.CreateHttpmanagmentpayload(orchestrationId);

return new OkObjectResult($"Thanks for your purchase");

}

//[ActivityTrigger] Order order // in activity funcs provide the trigger now and also helps tracking the workflow.




If you are interested in learning more about Azure Functions, there is a very good tutorial on Pluralsights - https://app.pluralsight.com/player?course=azure-functions-fundamentals&author=mark-heath&name=azure-functions-fundamentals-m0&clip=0&mode=live

Popular posts from this blog

Sitecore PowerShell Script to create all language versions for an item from en version

  We have lots of media items and our business wants to copy the data from en version of media item to all other language versions defined in System/Languages. This ensures that media is available in all the languages. So, we created the below powershell script to achieve the same -  #Get all language versions defined in System/Languages $languages = Get-ChildItem /sitecore/System/Languages -recurse | Select $_.name | Where-Object {$_.name -ne "en"} | Select Name #Ensuring correct items are updated by comparing the template ID  $items = Get-ChildItem -Path "/sitecore/media library/MyProjects" -Recurse | Where-Object {'<media item template id>' -contains $_.TemplateID} #Bulk update context to improve performance New-UsingBlock (New-Object Sitecore.Data.BulkUpdateContext) { foreach($item in $items){    foreach($language in $languages){ $languageVersion = Get-Item -Path $item.Paths.Path -Language $language.Name #Check if language versi

Export Sitecore media library files to zip using SPE

If you ever require to export Sitecore media files to zip (may be to optimize them), SPE (Sitecore Powershell Extension) has probably the easiest way to do this for you. It's as easy as the below 3 steps -  1. Right click on your folder (icons folder in snap)>Click on Scripts> Click on Download 2. SPE will start zipping all the media files placed within this folder. 3. Once zipping is done, you will see the Download option in the next screen. Click Download Zip containing the media files within is available on your local machine. You can play around with the images now. Hope this helps!! Like and Share ;)

Make Sitecore instance faster using Roslyn Compiler

When we install the Sitecore instance on local, the first load is slow. After each code deploy also, it takes a while for the Sitecore instance to load and experience editor to come up. For us, the load time for Sitecore instance on local machines was around 4 minutes. We started looking for ways to minimize it and found that if we update our Web.config to use Roslyn compiler and include the relevant Nugets into the project, our load times will improve. We followed the simple steps - Go to the Project you wish to add the NuGet package and right click the project and click 'Manage NuGet Packages'. Make sure your 'Package Source' is set to nuget.org and go to the 'Browse' Tab and search Microsoft.CodeDom.Providers.DotNetCompilerPlatform. Install whichever version you desire, make sure you note which version you installed. You can learn more about it  here . After installation, deploy your project, make sure the Microsoft.CodeDom.Providers.DotNetCompilerPlatform.d

Experience of a first time Sitecore MVP

The Journey I have been working in Sitecore for almost 10 years now. When I was a beginner in Sitecore, I was highly impressed by the incredible community support. In fact, my initial Sitecore learning path was entirely based on community written blogs on Sitecore. During a discussion with my then technology lead Neeraj Gulia , he proposed the idea that I should start giving back to developer community whenever I get chance. Just like I have been helped by many developers via online blogs, stackoverflow etc., I should also try to help others. Fast forward a few years and I met  Nehemiah Jeyakumar  (now an MVP). He had a big archive of his technical notes in the form Sitecore blogs. I realized my first blog dont have to be perfect and it can be as simple as notes to a specific problem for reference in future. That's when I probably created my first blog post on Sitecore. At that time, I didn't knew about the Sitecore MVP program. Over the years, I gained more confidence to write

Clean Coding Principles in CSharp

A code shall be easy to read and understand. In this post, I am outlining basic principles  about clean coding after researching through expert recommended books, trainings and based on my experience. A common example to start with is a variable declaration like - int i  The above statement did not clarify the purpose of variable i. However,  the same variable can be declared as -  int pageNumber The moment we declared the variable as int pageNumber, our brain realized that the variable is going to store the value for number of pages. We have set the context in our brain now and it is ready to understand what the code is going to do next with these page numbers. This is one of the basic advantages of clean coding. Reasons for clean coding -  • Reading clean code is easier - Every code is revisited after certain amount of time either by the same or different developer who created it. In both the cases, if the code is unclean, its difficult to understand and update it. • To avoid s