Handling your local directory in Azure Functions

Since Azure Functions are not a typical(and least in terms how they're executed) application, you may from time to time face a problems, which are not a case in more common solutions. One of those is a problem with storing local files. Consider following snippet:

/
using System.Net;
using System.IO;

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    File.WriteAllText("test.txt", "Foo");

    return req.CreateResponse(HttpStatusCode.OK, "Hello ");
}

when you run this code in as your function you will get following error:

/
2017-05-17T06:28:37.775 Exception while executing function: Functions.HttpTriggerCSharp1. mscorlib: Access to the path 'D:\Windows\system32\test.txt' is denied.

This is because if you don't provide a full path to your file, the default working directory of the process, inside which your functions runs, is D:\Windows\system32. Fortunately there's an easy fix to this.

Finding your local directory

The receipt to get your local directory is really simple. There's one thing to remember - your function app is hosted inside a following directory: D:\home\site\wwwroot. When you look at it, you can expect following structure:

/
home
	- site
		- wwwroot
			- Function1
			- Function2
			- ...

All we need to do here is to combine main directory path with the name of the function. That way we can modify the snippet from above slightly:

/
using System.Net;
using System.IO;

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    File.WriteAllText("D:\\home\\site\\wwwroot\\HttpTriggerCSharp1\\test.txt", "Foo");

    return req.CreateResponse(HttpStatusCode.OK, "Hello ");
}

and when we run it, you should see following output:

/
2017-05-17T06:43:29.408 Function started (Id=1baa9a60-d549-492d-8fef-089cd8e8de06)
2017-05-17T06:43:29.408 Function completed (Success, Id=1baa9a60-d549-492d-8fef-089cd8e8de06, Duration=4ms)

 

 

Azure Functions and Serverless - configuration and bindings

Azure Functions support in Serverless is still a fresh thing, yet it gives us plenty of different configuration options and bindings with many Azure components. In this post we'll quickly go through configuration file and compare Serverless implementation of functions with an original solution using Azure Portal or Visual Studio.

Configuration

In Serverless the file responsible for configuring a function app is named serverless.yml. If you go to the one attached to the boilerplate code, which you can using following command:

/
serverless install --url https://github.com/azure/boilerplate-azurefunctions

You'll see following structure:

/
service: azure-functions-app1234

provider:
  name: azure
  location: West US
  #armTemplate:
     #file: YourARMTemplate.json
     #parameters:
      #VariableNameToUserInArmTemplate: Value

plugins:
  - serverless-azure-functions

package:
  exclude:
    - node_modules/**
    - .gitignore
    - package.json
    - .git/**

functions:
  httpjs: 
     handler: handler.hello
     events: 
       - http: true
         x-azure-settings:
           authLevel : anonymous
           
  queuejs: 
     handler: handler.helloQueue
     events: 
       - queue: SampleQueue
         x-azure-settings:
           name: queueItem
           connection : AzureWebJobsStorage
       - blob:
         x-azure-settings:
           name: blobOut
           direction: out
           connection : AzureWebJobsStorage

As you can still you can store whole configuration and functions references in the only one file. This greatly improves manageability and helps in keeping a solution clean. Let's dive a bit deeper into it.

Bindings

There're planty of different bindings to choose from when working both with Azure Functions and Serverless. Currently you can use HTTP, Timer, Queue, Service Bus, Event Hub or Blob Storage. What is more, Serverless allows to use additional bindings like DocumentDB, Notification Hubs or Mobile Apps. In fact, because the implementation of bindings is something that you don't have to think about, whole solution is pretty flexible and straightforward. Let's compare serverless.yml with a basic C# example:

/
functions:
  example:
    handler: handler.hello
    events:
      - http: true
        x-azure-settings:
            name: req #<string>, default - "req", specifies which name it's available on `context.bindings` 
            methods: #<array> [GET, POST, PUT, DELETE], default - all
                - GET
            route: example/hello #<string>, default - <function name>
            authLevel: anonymous #<enum - anonymous|function (default)|admin>
/
{
    "disabled": false,
    "bindings": [
        {
            "name": "req",
            "type": "httpTrigger",
            "direction": "in",
            "authLevel": "function",
            "methods": [
                "post"
            ],
            "route": "example/hello"
        },
        {
            "name": "res",
            "type": "http",
            "direction": "out"
        }
    ]
}

As you can see, both configurations are quite similar. The main difference is the whole structure of a solution - when it comes to working with Serverless, you have a single file where it stores all the data.

Remember that if you'd like to use multiple bindings, each one will be available from the context.bindings array with a corresponding name. Consider this example:

/
/
functions:
  example:
    handler: handler.hello
    events:
      - http: true
        x-azure-settings:
            name: req #<string>, default - "req", specifies which name it's available on `context.bindings` 
            methods: #<array> [GET, POST, PUT, DELETE], default - all
                - GET
            route: example/hello #<string>, default - <function name>
            authLevel: anonymous #<enum - anonymous|function (default)|admin>
      - eventHub:
        x-azure-settings:
            name: item #<string>, default - "myEventHubMessage", specifies which name it's available on `context.bindings` 
            path: hello #<string>, specifies the Name of the Event Hub
            consumerGroup: $Default #<string>, default - "$Default", specifies the consumerGroup to listen with
            connection: EventHubsConnection #<string>, App Setting/environment variable which contains Event Hubs Namespace Connection String

In such case you'll have both context.bindings.req and context.bindings.item properties available and usable.

Examples for Serverless were taken from the official documentation.