Learn how to work with triggers and bindings in Azure Functions

This topic shows you how to use triggers and bindings in Azure Functions to connect your code to a variety of triggers and Azure services and other cloud-based services. It features some of the advanced binding features and syntax supported by all binding types.

For detailed information about working with a specific type of trigger or binding, see one of the following reference topics:

HTTP/webhook Timer Mobile Apps Service Bus
DocumentDB Storage Blob Storage Queue Storage Table
Event Hubs Notification Hubs SendGrid Twilio

These articles assume that you've read the Azure Functions developer reference, and the C#, F#, or Node.js developer reference articles.

Overview

Triggers are event responses used to trigger your custom code. They allow you to respond to events across the Azure platform or on premise. Bindings represent the necessary meta data used to connect your code to the desired trigger or associated input or output data. The function.json file for each function contains all related bindings. There is no limit to the number of input and output bindings a function can have. However, only a single trigger binding is supported for each function.

To get a better idea of the different bindings you can integrate with your Azure Function app, refer to the following table.

Type Service Trigger Input Output
Schedule Azure Functions
HTTP (REST or webhook) Azure Functions ✔*
Blob Storage Azure Storage
Events Azure Event Hubs
Queues Azure Storage
Queues and topics Azure Service Bus
Tables Azure Storage
Tables Azure Mobile Apps
No-SQL DB Azure DocumentDB
Push Notifications Azure Notification Hubs
Twilio SMS Text Twilio

(* - The HTTP output binding requires an HTTP trigger)

To better understand triggers and bindings in general, suppose you want to execute some code to process a new item dropped into an Azure Storage queue. Azure Functions provides an Azure Queue trigger to support this. You would need, the following information to monitor the queue:

  • The storage account where the queue exists.
  • The queue name.
  • A variable name that your code would use to refer to the new item that was dropped into the queue.

A queue trigger binding contains this information for an Azure function. Here is an example function.json containing a queue trigger binding.

{
  "bindings": [
    {
      "name": "myNewUserQueueItem",
      "type": "queueTrigger",
      "direction": "in",
      "queueName": "queue-newusers",
      "connection": "MY_STORAGE_ACCT_APP_SETTING"
    }
  ],
  "disabled": false
}

Your code may send different types of output depending on how the new queue item is processed. For example, you might want to write a new record to an Azure Storage table. To do this, you create an output binding to an Azure Storage table. Here is an example function.json that includes a storage table output binding that could be used with a queue trigger.

{
  "bindings": [
    {
      "name": "myNewUserQueueItem",
      "type": "queueTrigger",
      "direction": "in",
      "queueName": "queue-newusers",
      "connection": "MY_STORAGE_ACCT_APP_SETTING"
    },
    {
      "type": "table",
      "name": "myNewUserTableBinding",
      "tableName": "newUserTable",
      "connection": "MY_TABLE_STORAGE_ACCT_APP_SETTING",
      "direction": "out"
    }
  ],
  "disabled": false
}

The following C# function responds to a new item being dropped into the queue and writes a new user entry into an Azure Storage table.

#r "Newtonsoft.Json"

using System;
using Newtonsoft.Json;

public static async Task Run(string myNewUserQueueItem, IAsyncCollector<Person> myNewUserTableBinding, 
                                TraceWriter log)
{
    // In this example the queue item is a JSON string representing an order that contains the name, 
    // address and mobile number of the new customer.
    dynamic order = JsonConvert.DeserializeObject(myNewUserQueueItem);

    await myNewUserTableBinding.AddAsync(
        new Person() { 
            PartitionKey = "Test", 
            RowKey = Guid.NewGuid().ToString(), 
            Name = order.name,
            Address = order.address,
            MobileNumber = order.mobileNumber }
        );
}

public class Person
{
    public string PartitionKey { get; set; }
    public string RowKey { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
    public string MobileNumber { get; set; }
}

For more code examples and more specific information regarding Azure storage types that are supported, see Azure Functions triggers and bindings for Azure Storage.

To use the more advanced binding features in the Azure portal, click the Advanced editor option on the Integrate tab of your function. The advanced editor allows you to edit the function.json directly in the portal.

Random GUIDs

Azure Functions provides a syntax to generate random GUIDs with your bindings. The following binding syntax writes output to a new BLOB with a unique name in a Storage container:

{
  "type": "blob",
  "name": "blobOutput",
  "direction": "out",
  "path": "my-output-container/{rand-guid}"
}

Returning a single output

In cases where your function code returns a single output, you can use an output binding named $return to retain a more natural function signature in your code. This can only be used with languages that support a return value (C#, Node.js, F#). The binding would be similar to the following blob output binding that is used with a queue trigger.

{
  "bindings": [
    {
      "type": "queueTrigger",
      "name": "input",
      "direction": "in",
      "queueName": "test-input-node"
    },
    {
      "type": "blob",
      "name": "$return",
      "direction": "out",
      "path": "test-output-node/{id}"
    }
  ]
}

The following C# code returns the output more naturally without using an out parameter in the function signature.

public static string Run(WorkItem input, TraceWriter log)
{
    string json = string.Format("{{ \"id\": \"{0}\" }}", input.Id);
    log.Info($"C# script processed queue message. Item={json}");
    return json;
}

Async example:

public static Task<string> Run(WorkItem input, TraceWriter log)
{
    string json = string.Format("{{ \"id\": \"{0}\" }}", input.Id);
    log.Info($"C# script processed queue message. Item={json}");
    return json;
}

This same approach is demonstrated with Node.js, as follows:

module.exports = function (context, input) {
    var json = JSON.stringify(input);
    context.log('Node.js script processed queue message', json);
    context.done(null, json);
}

The following is an F# example:

let Run(input: WorkItem, log: TraceWriter) =
    let json = String.Format("{{ \"id\": \"{0}\" }}", input.Id)   
    log.Info(sprintf "F# script processed queue message '%s'" json)
    json

This can also be used with multiple output parameters by designating a single output with $return.

Resolving app settings

It is a best practice to store sensitive information as part of the run-time environment using app settings. By keeping sensitive information out of your app's configuration files, you limit exposure when a public repository is used to store app files.

The Azure Functions run-time resolves app settings to values when the app setting name is enclosed in percent signs, %your app setting%. The following Twilio binding uses an app setting named TWILIO_ACCT_PHONE for the from field of the binding.

{
  "type": "twilioSms",
  "name": "$return",
  "accountSid": "TwilioAccountSid",
  "authToken": "TwilioAuthToken",
  "to": "{mobileNumber}",
  "from": "%TWILIO_ACCT_PHONE%",
  "body": "Thank you {name}, your order was received Node.js",
  "direction": "out"
},

Parameter binding

Instead of a static configuration setting for your output binding properties, you can configure the settings to be dynamically bound to data that is part of your trigger's input binding. Consider a scenario where new orders are processed using an Azure Storage queue. Each new queue item is a JSON string containing at least the following properties:

{
  "name" : "Customer Name",
  "address" : "Customer's Address",
  "mobileNumber" : "Customer's mobile number in the format - +1XXXYYYZZZZ."
}

You might want to send the customer an SMS text message using your Twilio account as an update that the order was received. You can configure the body and to field of your Twilio output binding to be dynamically bound to the name and mobileNumber that were part of the input as follows.

{
  "name": "myNewOrderItem",
  "type": "queueTrigger",
  "direction": "in",
  "queueName": "queue-newOrders",
  "connection": "orders_STORAGE"
},
{
  "type": "twilioSms",
  "name": "$return",
  "accountSid": "TwilioAccountSid",
  "authToken": "TwilioAuthToken",
  "to": "{mobileNumber}",
  "from": "%TWILIO_ACCT_PHONE%",
  "body": "Thank you {name}, your order was received",
  "direction": "out"
},

Now your function code only has to initialize the output parameter as follows. During execution, the output properties are bound to the desired input data.

#r "Newtonsoft.Json"
#r "Twilio.Api"

using System;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Twilio;

public static async Task<SMSMessage> Run(string myNewOrderItem, TraceWriter log)
{
    log.Info($"C# Queue trigger function processed: {myNewOrderItem}");

    dynamic order = JsonConvert.DeserializeObject(myNewOrderItem);    

    // Even if you want to use a hard coded message and number in the binding, you must at least 
    // initialize the SMSMessage variable.
    SMSMessage smsText = new SMSMessage();

    // The following isn't needed since we use parameter binding for this
    //string msg = "Hello " + order.name + ", thank you for your order.";
    //smsText.Body = msg;
    //smsText.To = order.mobileNumber;

    return smsText;
}

Node.js:

module.exports = function (context, myNewOrderItem) {    
    context.log('Node.js queue trigger function processed work item', myNewOrderItem);    

    // No need to set the properties of the text, we use parameters in the binding. We do need to 
    // initialize the object.
    var smsText = {};    

    context.done(null, smsText);
}

Advanced binding at runtime (imperative binding)

The standard input and output binding pattern using function.json is called declarative binding, where the binding is defined by the JSON declaration. However, you can use imperative binding. With this patttern, you can bind to any number of supported input and output binding on-the-fly in your function code. You might need imperative binding in cases where the computation of binding path or other inputs needs to happen at run time in your function instead of design time.

Define an imperative binding as follows:

  • Do not include an entry in function.json for your desired imperative bindings.
  • Pass in an input parameter Binder binder or IBinder binder.
  • Use the following C# pattern to perform the data binding.
using (var output = await binder.BindAsync<T>(new BindingTypeAttribute(...)))
{
    ...
}

where BindingTypeAttribute is the .NET attribute that defines your binding and T is the input or output type that's supported by that binding type. T also cannot be an out parameter type (such as out JObject). For example, the Mobile Apps table output binding supports six output types, but you can only use ICollector or IAsyncCollector for T.

The following example code creates a Storage blob output binding with blob path that's defined at run time, then writes a string to the blob.

using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host.Bindings.Runtime;

public static async Task Run(string input, Binder binder)
{
    using (var writer = await binder.BindAsync<TextWriter>(new BlobAttribute("samples-output/path")))
    {
        writer.Write("Hello World!!");
    }
}

BlobAttribute defines the Storage blob input or output binding, and TextWriter is a supported output binding type. As is, the code gets the default app setting for the Storage account connection string (which is AzureWebJobsStorage). You can specify a custom app setting to use by adding the StorageAccountAttribute and passing the attribute array into BindAsync<T>(). For example,

using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host.Bindings.Runtime;

public static async Task Run(string input, Binder binder)
{
    var attributes = new Attribute[]
    {    
        new BlobAttribute("samples-output/path"),
        new StorageAccountAttribute("MyStorageAccount")
    };

    using (var writer = await binder.BindAsync<TextWriter>(attributes))
    {
        writer.Write("Hello World!");
    }
}

The following table shows you the corresponding .NET attribute to use for each binding type and which package to reference.

Binding Attribute Add reference
DocumentDB Microsoft.Azure.WebJobs.DocumentDBAttribute #r "Microsoft.Azure.WebJobs.Extensions.DocumentDB"
Event Hubs Microsoft.Azure.WebJobs.ServiceBus.EventHubAttribute, Microsoft.Azure.WebJobs.ServiceBusAccountAttribute #r "Microsoft.Azure.Jobs.ServiceBus"
Mobile Apps Microsoft.Azure.WebJobs.MobileTableAttribute #r "Microsoft.Azure.WebJobs.Extensions.MobileApps"
Notification Hubs Microsoft.Azure.WebJobs.NotificationHubAttribute #r "Microsoft.Azure.WebJobs.Extensions.NotificationHubs"
Service Bus Microsoft.Azure.WebJobs.ServiceBusAttribute, Microsoft.Azure.WebJobs.ServiceBusAccountAttribute #r "Microsoft.Azure.WebJobs.ServiceBus"
Storage queue Microsoft.Azure.WebJobs.QueueAttribute, Microsoft.Azure.WebJobs.StorageAccountAttribute
Storage blob Microsoft.Azure.WebJobs.BlobAttribute, Microsoft.Azure.WebJobs.StorageAccountAttribute
Storage table Microsoft.Azure.WebJobs.TableAttribute, Microsoft.Azure.WebJobs.StorageAccountAttribute
Twilio Microsoft.Azure.WebJobs.TwilioSmsAttribute #r "Microsoft.Azure.WebJobs.Extensions.Twilio"

Next steps

For more information, see the following resources: