Azure Functions File and Folder Structure

Posted by

I’ve been wanting to get a better understanding of how Azure Functions work from the ground up. So to accomplish that, I left the comfort zone of Visual Studio behind for the decidedly unfamiliar command line to understand the mechanics behind the creation, building, and running of Azure Functions via the Azure Functions Core Tools.

The information that I learned along the way led me to write this article, documenting the purpose of each of the files within an Azure Functions V2 project built with pre-compiled C# libraries.

Overview

The first step towards creating functions is accomplished by executing the func init command. It creates a project file that is configured for use with Azure Functions, and initializes the files needed to run functions locally and in the cloud. All functions within the project will be deployable as a single Function App on Azure.

With that done, it’s time to create a function by way of the func new command. The CLI tools ask you for the type of trigger you want (Http, Queue, Timer, etc.) and the Function’s name. The result will be a functionName.cs file at the root of the project that responds to the chosen trigger.

The resulting file and folder structure after running both commands looks like this:

FunctionAnatomy
Basic layout of an Azure Functions project

Let’s have a look to see what each of these files does for us.

Root Level Files

The .csproj file should be familiar to any .NET developer. It contains the configuration, references, and files used by the project. In the case of an Azure Functions project, the key part is to refer to the Microsoft.NET.Sdk.Functions package. This package tells the build tools where to find the needed assemblies to build the project.

Take note of the TargetFramework property in the project file. Until recently, the target framework for Azure Functions was .NET Standard 2.0. This limited the use of 3rd party packages to only those targeting .NET Standard 2.0. The Azure Functions team recently changed the target framework to .NET Core 2.1 instead, making it possible to also reference .NET Core libraries. It’s a small but welcome change that makes functions that much more flexible.

The host.json file contains configuration options that affect all functions within a Function App. The most commonly changed property is likely the function timeout, which can be configured anywhere from 1 to 10 minutes. The full list of configurable options is detailed here.

The local.settings.json file emulates the Application Settings that can be set at the Function App level through the portal. This is where you’d store any custom configuration settings that are needed by your function’s code. The .gitignore file that is generated by the CLI excludes this file from source control. There’s a few advantages to doing so:

  • The file is only needed to run functions locally and shouldn’t be deployed to Azure.
  • It prevents any secrets it may contain from getting pushed to source control.
  • It lets every developer have distinct configuration settings for storage, service bus, and connection strings.

The FunctionAnatomy.cs file is the Http trigger function that was generated when executing the func new command.

    public static class FunctionAnatomy
    {
        [FunctionName("HumanAnatomy")]
        public static async Task Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            HumanAnatomy data = JsonConvert.DeserializeObject(requestBody);

            return data != null
                ? (ActionResult)new OkObjectResult($"Muscles: {string.Join(",", data.muscles)}")
                : new BadRequestObjectResult("Something went wrong getting human anatomy.");
        }
    }

The FunctionName attribute makes the function discoverable by the function host when executing the func start --build command to run functions locally.

The first parameter passed to the Run(…) function differs based on the type of trigger being used. The attribute applied to the parameter is required and tells the function host how to expose the function. In the case above, the HttpTrigger attribute tells the function host that it should accept HTTP GET and HTTP POST requests.

The ILogger parameter logs messages from the execution of a function. Logging can be done through a TraceWriter or Application Insights. Both types of logs are visible in the function’s monitoring page in the Azure portal, with Application Insights providing a richer feature set for interpreting and analyzing the results.

Visual Studio Code generates a few metadata files in the .vscode folder to help us be more productive with functions. Most notably, it configures the debugger so that we can step through function code much like any other type of .NET application.

There’s one glaring omission from the files generated by the CLI, and that’s the .sln file that Visual Studio developers know as the root of most .NET solutions. The solution file isn’t needed if you’re working from the CLI or VsCode, but developers using Visual Studio will be prompted to create one if they do a Save All from the File menu.

Beyond The Root

It’s possible to write all the code needed for your functions at the root of the project. But much like other types of applications, as a function grows beyond the basics, it becomes necessary to break out the code into multiple folders and namespaces.

You can also move function triggers out of the root and into their own folders. The function host discovers the triggers so long as they have the FunctionName attribute. I recommend making a folder per Function if your Function App is going to have more than one or two functions. The end result would look much like this:

AnatomyFolders
Functions in folders

And that’s all there is to it. The Microsoft team have done an amazing job to give developers a simple experience with which to develop functions, be it from the CLI, Visual Studio, or VsCode.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s