Azure Functions V2

Azure functions have moved forward a huge amount since V1 in this post we go over some of the new changes to creating functions in V2.

This is the first part in a new updated series where I will update my functions to V2 and cover the new changes in Azure.

Setup

I created a small sample project with VSCode and setup some CI with the deployment center to deploy my changes.

Source code is here

I installed the tooling for VSCode

npm install -g azure-functions-core-tools

Azure Functions V1

Before in the V1 when we created a project for functions we would have different folders for each function. We don't need that in V2 with V2 we can create our function right in the root folder and set all the configuration we need there.

Azure Functions V2

The basics haven't changed. We still have the wide ranging triggers to use. In this post we're going to start by looking at the HTTP Trigger.

HTTP Trigger

In my project I want a new HTTP trigger. In my project I create a new file at route called "HTTPTrigger.cs" (or you can use VSCode to do it, pressing F1 - "Azure Functions - Create Function" I'll cover that in a later post)

Our function will look something like this.

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace Serversncode.Demo
{
    public static class HttpTrigger
    {
        [FunctionName("HttpTrigger")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "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 name != null
                ? (ActionResult)new OkObjectResult($"Hello, {name}")
                : new BadRequestObjectResult("Please pass a name on the query string or in the request body");
        }
    }
}

So what does all of this do? Mostly it's a normal C# file. But we have some things that are important for our Function.

[FunctionName("HttpTrigger")]

This does what you think. It sets the name for the function. (In V1 we would have put this all in a folder called HttpTrigger but in V2 we do it here through an attribute.)

        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)

Here we find the function work.

[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] 

AuthorizationLevel has 3 options:

Function - Function, Admin & System authorization level are key based. This allows anyone with the URL a function Key to access the function. Keys can be managed in the Azure portal

Anonymous - This will leave the URL with no token, so once someone has the URL they can access the Function

Admin - Admin authorization level requires a host key for authorization.

"get", "post"

These are the methods the Function is listening on.

In V2 we use

HttpRequest req, ILogger log

Instead of using

HttpRequestMessage req, TraceWriter log

After that the code is pretty much the same. In my sample it will check if there is a name in the body of the request.

If there is it prints it with "hello " if not you get a message asking to send a name.

I will have more posts following this where I go into more detail on the other function types and changes in V2. I'll also cover using VSCode and CI in more detail.