Azure Service Bus output binding for Azure Functions

Use Azure Service Bus output binding to send queue or topic messages.

For information on setup and configuration details, see the overview.

Important

This article uses tabs to support multiple versions of the Node.js programming model. The v4 model is currently in preview and is designed to have a more flexible and intuitive experience for JavaScript and TypeScript developers. Learn more about the differences between v3 and v4 in the upgrade guide.

Azure Functions supports two programming models for Python. The way that you define your bindings depends on your chosen programming model.

The Python v2 programming model lets you define bindings using decorators directly in your Python function code. For more information, see the Python developer guide.

This article supports both programming models.

Example

A C# function can be created using one of the following C# modes:

  • In-process class library: compiled C# function that runs in the same process as the Functions runtime.
  • Isolated worker process class library: compiled C# function that runs in a worker process that is isolated from the runtime. Isolated worker process is required to support C# functions running on non-LTS versions .NET and the .NET Framework.
  • C# script: used primarily when creating C# functions in the Azure portal.

This code defines and initializes the ILogger:

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using System.Threading.Tasks;
using Azure.Messaging.ServiceBus;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;

namespace SampleApp
{
    /// <summary>
    /// Samples demonstrating binding to the <see cref="ServiceBusReceivedMessage"/> type.
    /// </summary>
    public class ServiceBusReceivedMessageFunctions
    {
        //<docsnippet_servicebusmessage_createlogger>
        private readonly ILogger<ServiceBusReceivedMessageFunctions> _logger;

        public ServiceBusReceivedMessageFunctions(ILogger<ServiceBusReceivedMessageFunctions> logger)
        {
            _logger = logger;
        }
        //</docsnippet_servicebusmessage_createlogger>
        /// <summary>
        /// This function demonstrates binding to a single <see cref="ServiceBusReceivedMessage"/>.
        /// </summary>
        //<docsnippet_servicebus_readmessage>
        [Function(nameof(ServiceBusReceivedMessageFunction))]
        [ServiceBusOutput("outputQueue", Connection = "ServiceBusConnection")]
        public string ServiceBusReceivedMessageFunction(
            [ServiceBusTrigger("queue", Connection = "ServiceBusConnection")] ServiceBusReceivedMessage message)
        {
            _logger.LogInformation("Message ID: {id}", message.MessageId);
            _logger.LogInformation("Message Body: {body}", message.Body);
            _logger.LogInformation("Message Content-Type: {contentType}", message.ContentType);

            var outputMessage = $"Output message created at {DateTime.Now}";
            return outputMessage;
        }
        //</docsnippet_servicebus_readmessage>
        /// <summary>
        /// This function demonstrates binding to an array of <see cref="ServiceBusReceivedMessage"/>.
        /// Note that when doing so, you must also set the <see cref="ServiceBusTriggerAttribute.IsBatched"/> property
        /// to <value>true</value>.
        /// </summary>
        //<docsnippet_servicebus_readbatch>
        [Function(nameof(ServiceBusReceivedMessageBatchFunction))]
        public void ServiceBusReceivedMessageBatchFunction(
            [ServiceBusTrigger("queue", Connection = "ServiceBusConnection", IsBatched = true)] ServiceBusReceivedMessage[] messages)
        {
            foreach (ServiceBusReceivedMessage message in messages)
            {
                _logger.LogInformation("Message ID: {id}", message.MessageId);
                _logger.LogInformation("Message Body: {body}", message.Body);
                _logger.LogInformation("Message Content-Type: {contentType}", message.ContentType);
            }
        }
        //</docsnippet_servicebus_readbatch>
        /// <summary>
        /// This functions demonstrates that it is possible to bind to both the ServiceBusReceivedMessage and any of the supported binding contract
        /// properties at the same time. If attempting this, the ServiceBusReceivedMessage must be the first parameter. There is not
        /// much benefit to doing this as all of the binding contract properties are available as properties on the ServiceBusReceivedMessage.
        /// </summary>
        [Function(nameof(ServiceBusReceivedMessageWithStringProperties))]
        public void ServiceBusReceivedMessageWithStringProperties(
            [ServiceBusTrigger("queue", Connection = "ServiceBusConnection")]
            ServiceBusReceivedMessage message, string messageId, int deliveryCount)
        {
            // The MessageId property and the messageId parameter are the same.
            _logger.LogInformation("Message ID: {id}", message.MessageId);
            _logger.LogInformation("Message ID: {id}", messageId);

            // Similarly the DeliveryCount property and the deliveryCount parameter are the same.
            _logger.LogInformation("Delivery Count: {count}", message.DeliveryCount);
            _logger.LogInformation("Delivery Count: {count}", deliveryCount);
        }
        //<docsnippet_servicebus_message_actions>
        [Function(nameof(ServiceBusMessageActionsFunction))]
        public async Task ServiceBusMessageActionsFunction(
            [ServiceBusTrigger("queue", Connection = "ServiceBusConnection", AutoCompleteMessages = false)]
            ServiceBusReceivedMessage message,
            ServiceBusMessageActions messageActions)
        {
            _logger.LogInformation("Message ID: {id}", message.MessageId);
            _logger.LogInformation("Message Body: {body}", message.Body);
            _logger.LogInformation("Message Content-Type: {contentType}", message.ContentType);

            // Complete the message
            await messageActions.CompleteMessageAsync(message);
        }
        //</docsnippet_servicebus_message_actions>
    }
}

This example shows a C# function that receives a message and writes it to a second queue:

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using System.Threading.Tasks;
using Azure.Messaging.ServiceBus;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;

namespace SampleApp
{
    /// <summary>
    /// Samples demonstrating binding to the <see cref="ServiceBusReceivedMessage"/> type.
    /// </summary>
    public class ServiceBusReceivedMessageFunctions
    {
        //<docsnippet_servicebusmessage_createlogger>
        private readonly ILogger<ServiceBusReceivedMessageFunctions> _logger;

        public ServiceBusReceivedMessageFunctions(ILogger<ServiceBusReceivedMessageFunctions> logger)
        {
            _logger = logger;
        }
        //</docsnippet_servicebusmessage_createlogger>
        /// <summary>
        /// This function demonstrates binding to a single <see cref="ServiceBusReceivedMessage"/>.
        /// </summary>
        //<docsnippet_servicebus_readmessage>
        [Function(nameof(ServiceBusReceivedMessageFunction))]
        [ServiceBusOutput("outputQueue", Connection = "ServiceBusConnection")]
        public string ServiceBusReceivedMessageFunction(
            [ServiceBusTrigger("queue", Connection = "ServiceBusConnection")] ServiceBusReceivedMessage message)
        {
            _logger.LogInformation("Message ID: {id}", message.MessageId);
            _logger.LogInformation("Message Body: {body}", message.Body);
            _logger.LogInformation("Message Content-Type: {contentType}", message.ContentType);

            var outputMessage = $"Output message created at {DateTime.Now}";
            return outputMessage;
        }
        //</docsnippet_servicebus_readmessage>
        /// <summary>
        /// This function demonstrates binding to an array of <see cref="ServiceBusReceivedMessage"/>.
        /// Note that when doing so, you must also set the <see cref="ServiceBusTriggerAttribute.IsBatched"/> property
        /// to <value>true</value>.
        /// </summary>
        //<docsnippet_servicebus_readbatch>
        [Function(nameof(ServiceBusReceivedMessageBatchFunction))]
        public void ServiceBusReceivedMessageBatchFunction(
            [ServiceBusTrigger("queue", Connection = "ServiceBusConnection", IsBatched = true)] ServiceBusReceivedMessage[] messages)
        {
            foreach (ServiceBusReceivedMessage message in messages)
            {
                _logger.LogInformation("Message ID: {id}", message.MessageId);
                _logger.LogInformation("Message Body: {body}", message.Body);
                _logger.LogInformation("Message Content-Type: {contentType}", message.ContentType);
            }
        }
        //</docsnippet_servicebus_readbatch>
        /// <summary>
        /// This functions demonstrates that it is possible to bind to both the ServiceBusReceivedMessage and any of the supported binding contract
        /// properties at the same time. If attempting this, the ServiceBusReceivedMessage must be the first parameter. There is not
        /// much benefit to doing this as all of the binding contract properties are available as properties on the ServiceBusReceivedMessage.
        /// </summary>
        [Function(nameof(ServiceBusReceivedMessageWithStringProperties))]
        public void ServiceBusReceivedMessageWithStringProperties(
            [ServiceBusTrigger("queue", Connection = "ServiceBusConnection")]
            ServiceBusReceivedMessage message, string messageId, int deliveryCount)
        {
            // The MessageId property and the messageId parameter are the same.
            _logger.LogInformation("Message ID: {id}", message.MessageId);
            _logger.LogInformation("Message ID: {id}", messageId);

            // Similarly the DeliveryCount property and the deliveryCount parameter are the same.
            _logger.LogInformation("Delivery Count: {count}", message.DeliveryCount);
            _logger.LogInformation("Delivery Count: {count}", deliveryCount);
        }
        //<docsnippet_servicebus_message_actions>
        [Function(nameof(ServiceBusMessageActionsFunction))]
        public async Task ServiceBusMessageActionsFunction(
            [ServiceBusTrigger("queue", Connection = "ServiceBusConnection", AutoCompleteMessages = false)]
            ServiceBusReceivedMessage message,
            ServiceBusMessageActions messageActions)
        {
            _logger.LogInformation("Message ID: {id}", message.MessageId);
            _logger.LogInformation("Message Body: {body}", message.Body);
            _logger.LogInformation("Message Content-Type: {contentType}", message.ContentType);

            // Complete the message
            await messageActions.CompleteMessageAsync(message);
        }
        //</docsnippet_servicebus_message_actions>
    }
}

 


This example uses an HTTP trigger with an OutputType object to both send an HTTP response and write the output message.

[Function("HttpSendMsg")]
public async Task<OutputType> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req, FunctionContext context)
{
   _logger.LogInformation($"C# HTTP trigger function processed a request for {context.InvocationId}.");

   HttpResponseData response = req.CreateResponse(HttpStatusCode.OK);
   await response.WriteStringAsync("HTTP response: Message sent");

   return new OutputType()
   {
       OutputEvent = "MyMessage",
       HttpResponse = response
   };
}

This code defines the multiple output type OutputType, which includes the Service Bus output binding definition on OutputEvent:

 public class OutputType
{
   [ServiceBusOutput("TopicOrQueueName", Connection = "ServiceBusConnection")]
   public string OutputEvent { get; set; }

   public HttpResponseData HttpResponse { get; set; }
}

The following example shows a Java function that sends a message to a Service Bus queue myqueue when triggered by an HTTP request.

@FunctionName("httpToServiceBusQueue")
@ServiceBusQueueOutput(name = "message", queueName = "myqueue", connection = "AzureServiceBusConnection")
public String pushToQueue(
  @HttpTrigger(name = "request", methods = {HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS)
  final String message,
  @HttpOutput(name = "response") final OutputBinding<T> result ) {
      result.setValue(message + " has been sent.");
      return message;
 }

In the Java functions runtime library, use the @QueueOutput annotation on function parameters whose value would be written to a Service Bus queue. The parameter type should be OutputBinding<T>, where T is any native Java type of a POJO.

Java functions can also write to a Service Bus topic. The following example uses the @ServiceBusTopicOutput annotation to describe the configuration for the output binding.

@FunctionName("sbtopicsend")
    public HttpResponseMessage run(
            @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
            @ServiceBusTopicOutput(name = "message", topicName = "mytopicname", subscriptionName = "mysubscription", connection = "ServiceBusConnection") OutputBinding<String> message,
            final ExecutionContext context) {

        String name = request.getBody().orElse("Azure Functions");

        message.setValue(name);
        return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();

    }

The following example shows a timer triggered TypeScript function that sends a queue message every 5 minutes.

import { app, InvocationContext, output, Timer } from '@azure/functions';

export async function timerTrigger1(myTimer: Timer, context: InvocationContext): Promise<string> {
    const timeStamp = new Date().toISOString();
    return `Message created at: ${timeStamp}`;
}

app.timer('timerTrigger1', {
    schedule: '0 */5 * * * *',
    return: output.serviceBusQueue({
        queueName: 'testqueue',
        connection: 'MyServiceBusConnection',
    }),
    handler: timerTrigger1,
});

To output multiple messages, return an array instead of a single object. For example:

import { app, InvocationContext, output, Timer } from '@azure/functions';

export async function timerTrigger1(myTimer: Timer, context: InvocationContext): Promise<string[]> {
    // <displayInDocs>
    const timeStamp = new Date().toISOString();
    const message = `Message created at: ${timeStamp}`;
    return [`1: ${message}`, `2: ${message}`];
    // </displayInDocs>
}

app.timer('timerTrigger1', {
    schedule: '0 */5 * * * *',
    return: output.serviceBusQueue({
        queueName: 'testqueue',
        connection: 'MyServiceBusConnection',
    }),
    handler: timerTrigger1,
});

The following example shows a timer triggered JavaScript function that sends a queue message every 5 minutes.

const { app, output } = require('@azure/functions');

const serviceBusOutput = output.serviceBusQueue({
    queueName: 'testqueue',
    connection: 'MyServiceBusConnection',
});

app.timer('timerTrigger1', {
    schedule: '0 */5 * * * *',
    return: serviceBusOutput,
    handler: (myTimer, context) => {
        const timeStamp = new Date().toISOString();
        return `Message created at: ${timeStamp}`;
    },
});

To output multiple messages, return an array instead of a single object. For example:

const { app, output } = require('@azure/functions');

const serviceBusOutput = output.serviceBusQueue({
    queueName: 'testqueue',
    connection: 'MyServiceBusConnection',
});

app.timer('timerTrigger1', {
    schedule: '0 */5 * * * *',
    return: serviceBusOutput,
    handler: (myTimer, context) => {
        // <displayInDocs>
        const timeStamp = new Date().toISOString();
        const message = `Message created at: ${timeStamp}`;
        return [`1: ${message}`, `2: ${message}`];
        // </displayInDocs>
    },
});

The following example shows a Service Bus output binding in a function.json file and a PowerShell function that uses the binding.

Here's the binding data in the function.json file:

{
  "bindings": [
    {
      "type": "serviceBus",
      "direction": "out",
      "connection": "AzureServiceBusConnectionString",
      "name": "outputSbMsg",
      "queueName": "outqueue",
      "topicName": "outtopic"
    }
  ]
}

Here's the PowerShell that creates a message as the function's output.

param($QueueItem, $TriggerMetadata) 

Push-OutputBinding -Name outputSbMsg -Value @{ 
    name = $QueueItem.name 
    employeeId = $QueueItem.employeeId 
    address = $QueueItem.address 
} 

The following example demonstrates how to write out to a Service Bus queue in Python. The example depends on whether you use the v1 or v2 Python programming model.

import logging
import azure.functions as func

app = func.FunctionApp()

@app.route(route="put_message")
@app.service_bus_topic_output(arg_name="message",
                              connection="<CONNECTION_SETTING>",
                              topic_name="<TOPIC_NAME>")
def main(req: func.HttpRequest, message: func.Out[str]) -> func.HttpResponse:
    input_msg = req.params.get('message')
    message.set(input_msg)
    return 'OK'

Attributes

Both in-process and isolated worker process C# libraries use attributes to define the output binding. C# script instead uses a function.json configuration file as described in the C# scripting guide.

In C# class libraries, use the ServiceBusOutputAttribute to define the queue or topic written to by the output.

The following table explains the properties you can set using the attribute:

Property Description
EntityType Sets the entity type as either Queue for sending messages to a queue or Topic when sending messages to a topic.
QueueOrTopicName Name of the topic or queue to send messages to. Use EntityType to set the destination type.
Connection The name of an app setting or setting collection that specifies how to connect to Service Bus. See Connections.

Decorators

Applies only to the Python v2 programming model.

For Python v2 functions defined using a decorator, the following properties on the service_bus_topic_output:

Property Description
arg_name The name of the variable that represents the queue or topic message in function code.
queue_name Name of the queue. Set only if sending queue messages, not for a topic.
topic_name Name of the topic. Set only if sending topic messages, not for a queue.
connection The name of an app setting or setting collection that specifies how to connect to Service Bus. See Connections.

For Python functions defined by using function.json, see the Configuration section.

Annotations

The ServiceBusQueueOutput and ServiceBusTopicOutput annotations are available to write a message as a function output. The parameter decorated with these annotations must be declared as an OutputBinding<T> where T is the type corresponding to the message's type.

When you're developing locally, add your application settings in the local.settings.json file in the Values collection.

Configuration

Applies only to the Python v1 programming model.

The following table explains the properties that you can set on the options object passed to the output.serviceBusQueue() method.

Property Description
queueName Name of the queue.
connection The name of an app setting or setting collection that specifies how to connect to Service Bus. See Connections.

The following table explains the properties that you can set on the options object passed to the output.serviceBusTopic() method.

Property Description
topicName Name of the topic.
connection The name of an app setting or setting collection that specifies how to connect to Service Bus. See Connections.

When you're developing locally, add your application settings in the local.settings.json file in the Values collection.

The following table explains the binding configuration properties that you set in the function.json file and the ServiceBus attribute.

function.json property Description
type Must be set to "serviceBus". This property is set automatically when you create the trigger in the Azure portal.
direction Must be set to "out". This property is set automatically when you create the trigger in the Azure portal.
name The name of the variable that represents the queue or topic message in function code. Set to "$return" to reference the function return value.
queueName Name of the queue. Set only if sending queue messages, not for a topic.
topicName Name of the topic. Set only if sending topic messages, not for a queue.
connection The name of an app setting or setting collection that specifies how to connect to Service Bus. See Connections.
accessRights (v1 only) Access rights for the connection string. Available values are manage and listen. The default is manage, which indicates that the connection has the Manage permission. If you use a connection string that does not have the Manage permission, set accessRights to "listen". Otherwise, the Functions runtime might fail trying to do operations that require manage rights. In Azure Functions version 2.x and higher, this property is not available because the latest version of the Service Bus SDK doesn't support manage operations.

When you're developing locally, add your application settings in the local.settings.json file in the Values collection.

See the Example section for complete examples.

Usage

The following output parameter types are supported by all C# modalities and extension versions:

Type Description
System.String Use when the message to write is simple text. When the parameter value is null when the function exits, Functions doesn't create a message.
byte[] Use for writing binary data messages. When the parameter value is null when the function exits, Functions doesn't create a message.
Object When a message contains JSON, Functions serializes the object into a JSON message payload. When the parameter value is null when the function exits, Functions creates a message with a null object.

Messaging-specific parameter types contain additional message metadata. The specific types supported by the output binding depend on the Functions runtime version, the extension package version, and the C# modality used.

When you want the function to write a single message, the Service Bus output binding can bind to the following types:

Type Description
string The message as a string. Use when the message is simple text.
byte[] The bytes of the message.
JSON serializable types An object representing the message. Functions attempts to serialize a plain-old CLR object (POCO) type into JSON data.

When you want the function to write multiple messages, the Service Bus output binding can bind to the following types:

Type Description
T[] where T is one of the single message types An array containing multiple message. Each entry represents one message.

For other output scenarios, create and use types from Azure.Messaging.ServiceBus directly.

In Azure Functions 1.x, the runtime creates the queue if it doesn't exist and you have set accessRights to manage. In Azure Functions version 2.x and higher, the queue or topic must already exist; if you specify a queue or topic that doesn't exist, the function fails.

Use the Azure Service Bus SDK rather than the built-in output binding.

Access the output message by returning the value directly or using context.extraOutputs.set().

Output to the Service Bus is available via the Push-OutputBinding cmdlet where you pass arguments that match the name designated by binding's name parameter in the function.json file.

Use the Azure Service Bus SDK rather than the built-in output binding.

For a complete example, see the examples section.

Connections

The connection property is a reference to environment configuration which specifies how the app should connect to Service Bus. It may specify:

If the configured value is both an exact match for a single setting and a prefix match for other settings, the exact match is used.

Connection string

To obtain a connection string, follow the steps shown at Get the management credentials. The connection string must be for a Service Bus namespace, not limited to a specific queue or topic.

This connection string should be stored in an application setting with a name matching the value specified by the connection property of the binding configuration.

If the app setting name begins with "AzureWebJobs", you can specify only the remainder of the name. For example, if you set connection to "MyServiceBus", the Functions runtime looks for an app setting that is named "AzureWebJobsMyServiceBus". If you leave connection empty, the Functions runtime uses the default Service Bus connection string in the app setting that is named "AzureWebJobsServiceBus".

Identity-based connections

If you are using version 5.x or higher of the extension, instead of using a connection string with a secret, you can have the app use an Azure Active Directory identity. To do this, you would define settings under a common prefix which maps to the connection property in the trigger and binding configuration.

In this mode, the extension requires the following properties:

Property Environment variable template Description Example value
Fully Qualified Namespace <CONNECTION_NAME_PREFIX>__fullyQualifiedNamespace The fully qualified Service Bus namespace. <service_bus_namespace>.servicebus.chinacloudapi.cn

Additional properties may be set to customize the connection. See Common properties for identity-based connections.

Note

When using Azure App Configuration or Key Vault to provide settings for Managed Identity connections, setting names should use a valid key separator such as : or / in place of the __ to ensure names are resolved correctly.

For example, <CONNECTION_NAME_PREFIX>:fullyQualifiedNamespace.

When hosted in the Azure Functions service, identity-based connections use a managed identity. The system-assigned identity is used by default, although a user-assigned identity can be specified with the credential and clientID properties. Note that configuring a user-assigned identity with a resource ID is not supported. When run in other contexts, such as local development, your developer identity is used instead, although this can be customized. See Local development with identity-based connections.

Grant permission to the identity

Whatever identity is being used must have permissions to perform the intended actions. For most Azure services, this means you need to assign a role in Azure RBAC, using either built-in or custom roles which provide those permissions.

Important

Some permissions might be exposed by the target service that are not necessary for all contexts. Where possible, adhere to the principle of least privilege, granting the identity only required privileges. For example, if the app only needs to be able to read from a data source, use a role that only has permission to read. It would be inappropriate to assign a role that also allows writing to that service, as this would be excessive permission for a read operation. Similarly, you would want to ensure the role assignment is scoped only over the resources that need to be read.

You'll need to create a role assignment that provides access to your topics and queues at runtime. Management roles like Owner aren't sufficient. The following table shows built-in roles that are recommended when using the Service Bus extension in normal operation. Your application may require additional permissions based on the code you write.

Binding type Example built-in roles
Trigger1 Azure Service Bus Data Receiver, Azure Service Bus Data Owner
Output binding Azure Service Bus Data Sender

1 For triggering from Service Bus topics, the role assignment needs to have effective scope over the Service Bus subscription resource. If only the topic is included, an error will occur. Some clients, such as the Azure portal, don't expose the Service Bus subscription resource as a scope for role assignment. In such cases, the Azure CLI may be used instead. To learn more, see Azure built-in roles for Azure Service Bus.

Exceptions and return codes

Binding Reference
Service Bus Service Bus Error Codes
Service Bus Service Bus Limits

Next steps