Azure Blob storage bindings for Azure Functions

This article explains how to work with Azure Blob storage bindings in Azure Functions. Azure Functions supports trigger, input, and output bindings for blobs. The article includes a section for each binding:

This is reference information for Azure Functions developers. If you're new to Azure Functions, start with the following resources:

Note

Use the Event Grid trigger instead of the Blob storage trigger for blob-only storage accounts, for high scale, or to reduce latency. For more information, see the Trigger section.

Packages - Functions 1.x

The Blob storage bindings are provided in the Microsoft.Azure.WebJobs NuGet package, version 2.x. Source code for the package is in the azure-webjobs-sdk GitHub repository.

Support for this binding is automatically provided in all development environments. You don't have to manually install the package or register the extension.

Azure Storage SDK version in Functions 1.x

In Functions 1.x, the Storage triggers and bindings use version 7.2.1 of the Azure Storage SDK (WindowsAzure.Storage NuGet package). If you reference a different version of the Storage SDK, and you bind to a Storage SDK type in your function signature, the Functions runtime may report that it can't bind to that type. The solution is to make sure your project references WindowsAzure.Storage 7.2.1.

Packages - Functions 2.x

The Blob storage bindings are provided in the Microsoft.Azure.WebJobs.Extensions.Storage NuGet package, version 3.x. Source code for the package is in the azure-webjobs-sdk GitHub repository.

The following table tells how to add support for this binding in each development environment.

Development environment To add support in
Functions 2.x
Local development - C# class library Install the package
Local development - C# script, JavaScript, F#, Java and Python Register the extension
Portal development Install when adding output binding

To learn how to update existing binding extensions in the portal without having to republish your function app project, see Update your extensions.

Trigger

The Blob storage trigger starts a function when a new or updated blob is detected. The blob contents are provided as input to the function.

The Event Grid trigger has built-in support for blob events and can also be used to start a function when a new or updated blob is detected. For an example, see the Image resize with Event Grid tutorial.

Use Event Grid instead of the Blob storage trigger for the following scenarios:

  • Blob storage accounts
  • High scale
  • Minimizing latency

Blob storage accounts

Blob storage accounts are supported for blob input and output bindings but not for blob triggers. Blob storage triggers require a general-purpose storage account.

High scale

High scale can be loosely defined as containers that have more than 100,000 blobs in them or storage accounts that have more than 100 blob updates per second.

Latency issues

If your function app is on the Consumption plan, there can be up to a 10-minute delay in processing new blobs if a function app has gone idle. To avoid this latency, you can switch to an App Service plan with Always On enabled. You can also use an Event Grid trigger with your Blob storage account. For an example, see the Event Grid tutorial.

Queue storage trigger

Besides Event Grid, another alternative for processing blobs is the Queue storage trigger, but it has no built-in support for blob events. You would have to create queue messages when creating or updating blobs. For an example that assumes you've done that, see the blob input binding example later in this article.

Trigger - example

See the language-specific example:

Trigger - C# example

The following example shows a C# function that writes a log when a blob is added or updated in the samples-workitems container.

[FunctionName("BlobTriggerCSharp")]        
public static void Run([BlobTrigger("samples-workitems/{name}")] Stream myBlob, string name, ILogger log)
{
    log.LogInformation($"C# Blob trigger function Processed blob\n Name:{name} \n Size: {myBlob.Length} Bytes");
}

The string {name} in the blob trigger path samples-workitems/{name} creates a binding expression that you can use in function code to access the file name of the triggering blob. For more information, see Blob name patterns later in this article.

For more information about the BlobTrigger attribute, see Trigger - attributes.

Trigger - C# script example

The following example shows a blob trigger binding in a function.json file and Python code that uses the binding. The function writes a log when a blob is added or updated in the samples-workitems container.

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

{
    "disabled": false,
    "bindings": [
        {
            "name": "myBlob",
            "type": "blobTrigger",
            "direction": "in",
            "path": "samples-workitems/{name}",
            "connection":"MyStorageAccountAppSetting"
        }
    ]
}

The string {name} in the blob trigger path samples-workitems/{name} creates a binding expression that you can use in function code to access the file name of the triggering blob. For more information, see Blob name patterns later in this article.

For more information about function.json file properties, see the Configuration section explains these properties.

Here's C# script code that binds to a Stream:

public static void Run(Stream myBlob, string name, ILogger log)
{
   log.LogInformation($"C# Blob trigger function Processed blob\n Name:{name} \n Size: {myBlob.Length} Bytes");
}

Here's C# script code that binds to a CloudBlockBlob:

#r "Microsoft.WindowsAzure.Storage"

using Microsoft.WindowsAzure.Storage.Blob;

public static void Run(CloudBlockBlob myBlob, string name, ILogger log)
{
    log.LogInformation($"C# Blob trigger function Processed blob\n Name:{name}\nURI:{myBlob.StorageUri}");
}

Trigger - JavaScript example

The following example shows a blob trigger binding in a function.json file and JavaScript code that uses the binding. The function writes a log when a blob is added or updated in the samples-workitems container.

Here's the function.json file:

{
    "disabled": false,
    "bindings": [
        {
            "name": "myBlob",
            "type": "blobTrigger",
            "direction": "in",
            "path": "samples-workitems/{name}",
            "connection":"MyStorageAccountAppSetting"
        }
    ]
}

The string {name} in the blob trigger path samples-workitems/{name} creates a binding expression that you can use in function code to access the file name of the triggering blob. For more information, see Blob name patterns later in this article.

For more information about function.json file properties, see the Configuration section explains these properties.

Here's the JavaScript code:

module.exports = function(context) {
    context.log('Node.js Blob trigger function processed', context.bindings.myBlob);
    context.done();
};

Trigger - Python example

The following example shows a blob trigger binding in a function.json file and Python code that uses the binding. The function writes a log when a blob is added or updated in the samples-workitems container.

Here's the function.json file:

{
    "scriptFile": "__init__.py",
    "disabled": false,
    "bindings": [
        {
            "name": "myblob",
            "type": "blobTrigger",
            "direction": "in",
            "path": "samples-workitems/{name}",
            "connection":"MyStorageAccountAppSetting"
        }
    ]
}

The string {name} in the blob trigger path samples-workitems/{name} creates a binding expression that you can use in function code to access the file name of the triggering blob. For more information, see Blob name patterns later in this article.

For more information about function.json file properties, see the Configuration section explains these properties.

Here's the Python code:

import logging
import azure.functions as func


def main(myblob: func.InputStream):
    logging.info('Python Blob trigger function processed %s', myblob.name)

Trigger - Java example

The following example shows a blob trigger binding in a function.json file and Java code that uses the binding. The function writes a log when a blob is added or updated in the myblob container.

Here's the function.json file:

{
    "disabled": false,
    "bindings": [
        {
            "name": "file",
            "type": "blobTrigger",
            "direction": "in",
            "path": "myblob/{name}",
            "connection":"MyStorageAccountAppSetting"
        }
    ]
}

Here's the Java code:

@FunctionName("blobprocessor")
public void run(
  @BlobTrigger(name = "file",
               dataType = "binary",
               path = "myblob/{name}",
               connection = "MyStorageAccountAppSetting") byte[] content,
  @BindingName("name") String filename,
  final ExecutionContext context
) {
  context.getLogger().info("Name: " + filename + " Size: " + content.length + " bytes");
}

Trigger - attributes

In C# class libraries, use the following attributes to configure a blob trigger:

  • BlobTriggerAttribute

    The attribute's constructor takes a path string that indicates the container to watch and optionally a blob name pattern. Here's an example:

    [FunctionName("ResizeImage")]
    public static void Run(
        [BlobTrigger("sample-images/{name}")] Stream image,
        [Blob("sample-images-md/{name}", FileAccess.Write)] Stream imageSmall)
    {
        ....
    }
    

    You can set the Connection property to specify the storage account to use, as shown in the following example:

    [FunctionName("ResizeImage")]
    public static void Run(
        [BlobTrigger("sample-images/{name}", Connection = "StorageConnectionAppSetting")] Stream image,
        [Blob("sample-images-md/{name}", FileAccess.Write)] Stream imageSmall)
    {
        ....
    }
    

    For a complete example, see Trigger - C# example.

  • StorageAccountAttribute

    Provides another way to specify the storage account to use. The constructor takes the name of an app setting that contains a storage connection string. The attribute can be applied at the parameter, method, or class level. The following example shows class level and method level:

    [StorageAccount("ClassLevelStorageAppSetting")]
    public static class AzureFunctions
    {
        [FunctionName("BlobTrigger")]
        [StorageAccount("FunctionLevelStorageAppSetting")]
        public static void Run( //...
    {
        ....
    }
    

The storage account to use is determined in the following order:

  • The BlobTrigger attribute's Connection property.
  • The StorageAccount attribute applied to the same parameter as the BlobTrigger attribute.
  • The StorageAccount attribute applied to the function.
  • The StorageAccount attribute applied to the class.
  • The default storage account for the function app ("AzureWebJobsStorage" app setting).

Trigger - configuration

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

function.json property Attribute property Description
type n/a Must be set to blobTrigger. This property is set automatically when you create the trigger in the Azure portal.
direction n/a Must be set to in. This property is set automatically when you create the trigger in the Azure portal. Exceptions are noted in the usage section.
name n/a The name of the variable that represents the blob in function code.
path BlobPath The container to monitor. May be a blob name pattern.
connection Connection The name of an app setting that contains the Storage connection string to use for this binding. If the app setting name begins with "AzureWebJobs", you can specify only the remainder of the name here. For example, if you set connection to "MyStorage", the Functions runtime looks for an app setting that is named "AzureWebJobsMyStorage." If you leave connection empty, the Functions runtime uses the default Storage connection string in the app setting that is named AzureWebJobsStorage.

The connection string must be for a general-purpose storage account, not a Blob storage account.

When you're developing locally, app settings go into the local.settings.json file.

Trigger - usage

In C# and C# script, you can use the following parameter types for the triggering blob:

  • Stream
  • TextReader
  • string
  • Byte[]
  • A POCO serializable as JSON
  • ICloudBlob1
  • CloudBlockBlob1
  • CloudPageBlob1
  • CloudAppendBlob1

1 Requires "inout" binding direction in function.json or FileAccess.ReadWrite in a C# class library.

If you try to bind to one of the Storage SDK types and get an error message, make sure that you have a reference to the correct Storage SDK version.

Binding to string, Byte[], or POCO is only recommended if the blob size is small, as the entire blob contents are loaded into memory. Generally, it is preferable to use a Stream or CloudBlockBlob type. For more information, see Concurrency and memory usage later in this article.

In JavaScript, access the input blob data using context.bindings.<name from function.json>.

Trigger - blob name patterns

You can specify a blob name pattern in the path property in function.json or in the BlobTrigger attribute constructor. The name pattern can be a filter or binding expression. The following sections provide examples.

Get file name and extension

The following example shows how to bind to the blob file name and extension separately:

"path": "input/{blobname}.{blobextension}",

If the blob is named original-Blob1.txt, the values of the blobname and blobextension variables in function code are original-Blob1 and txt.

Filter on blob name

The following example triggers only on blobs in the input container that start with the string "original-":

"path": "input/original-{name}",

If the blob name is original-Blob1.txt, the value of the name variable in function code is Blob1.

Filter on file type

The following example triggers only on .png files:

"path": "samples/{name}.png",

Filter on curly braces in file names

To look for curly braces in file names, escape the braces by using two braces. The following example filters for blobs that have curly braces in the name:

"path": "images/{{20140101}}-{name}",

If the blob is named {20140101}-soundfile.mp3, the name variable value in the function code is soundfile.mp3.

Trigger - metadata

The blob trigger provides several metadata properties. These properties can be used as part of binding expressions in other bindings or as parameters in your code. These values have the same semantics as the Cloud​Blob type.

Property Type Description
BlobTrigger string The path to the triggering blob.
Uri System.Uri The blob's URI for the primary location.
Properties BlobProperties The blob's system properties.
Metadata IDictionary<string,string> The user-defined metadata for the blob.

For example, the following C# script and JavaScript examples log the path to the triggering blob, including the container:

public static void Run(string myBlob, string blobTrigger, ILogger log)
{
    log.LogInformation($"Full blob path: {blobTrigger}");
} 
module.exports = function (context, myBlob) {
    context.log("Full blob path:", context.bindingData.blobTrigger);
    context.done();
};

Trigger - blob receipts

The Azure Functions runtime ensures that no blob trigger function gets called more than once for the same new or updated blob. To determine if a given blob version has been processed, it maintains blob receipts.

Azure Functions stores blob receipts in a container named azure-webjobs-hosts in the Azure storage account for your function app (defined by the app setting AzureWebJobsStorage). A blob receipt has the following information:

  • The triggered function ("<function app name>.Functions.<function name>", for example: "MyFunctionApp.Functions.CopyBlob")
  • The container name
  • The blob type ("BlockBlob" or "PageBlob")
  • The blob name
  • The ETag (a blob version identifier, for example: "0x8D1DC6E70A277EF")

To force reprocessing of a blob, delete the blob receipt for that blob from the azure-webjobs-hosts container manually. While reprocessing might not occur immediately, it's guaranteed to occur at a later point in time.

Trigger - poison blobs

When a blob trigger function fails for a given blob, Azure Functions retries that function a total of 5 times by default.

If all 5 tries fail, Azure Functions adds a message to a Storage queue named webjobs-blobtrigger-poison. The queue message for poison blobs is a JSON object that contains the following properties:

  • FunctionId (in the format <function app name>.Functions.<function name>)
  • BlobType ("BlockBlob" or "PageBlob")
  • ContainerName
  • BlobName
  • ETag (a blob version identifier, for example: "0x8D1DC6E70A277EF")

Trigger - concurrency and memory usage

The blob trigger uses a queue internally, so the maximum number of concurrent function invocations is controlled by the queues configuration in host.json. The default settings limit concurrency to 24 invocations. This limit applies separately to each function that uses a blob trigger.

The consumption plan limits a function app on one virtual machine (VM) to 1.5 GB of memory. Memory is used by each concurrently executing function instance and by the Functions runtime itself. If a blob-triggered function loads the entire blob into memory, the maximum memory used by that function just for blobs is 24 * maximum blob size. For example, a function app with three blob-triggered functions and the default settings would have a maximum per-VM concurrency of 3*24 = 72 function invocations.

JavaScript and Java functions load the entire blob into memory, and C# functions do that if you bind to string, Byte[], or POCO.

Trigger - polling

If the blob container being monitored contains more than 10,000 blobs (across all containers), the Functions runtime scans log files to watch for new or changed blobs. This process can result in delays. A function might not get triggered until several minutes or longer after the blob is created.

Warning

In addition, storage logs are created on a "best effort" basis. There's no guarantee that all events are captured. Under some conditions, logs may be missed.

If you require faster or more reliable blob processing, consider creating a queue message when you create the blob. Then use a queue trigger instead of a blob trigger to process the blob. Another option is to use Event Grid; see the tutorial Automate resizing uploaded images using Event Grid.

Input

Use a Blob storage input binding to read blobs.

Input - example

See the language-specific example:

Input - C# example

The following example is a C# function that uses a queue trigger and an input blob binding. The queue message contains the name of the blob, and the function logs the size of the blob.

[FunctionName("BlobInput")]
public static void Run(
    [QueueTrigger("myqueue-items")] string myQueueItem,
    [Blob("samples-workitems/{queueTrigger}", FileAccess.Read)] Stream myBlob,
    ILogger log)
{
    log.LogInformation($"BlobInput processed blob\n Name:{myQueueItem} \n Size: {myBlob.Length} bytes");
}

Input - C# script example

The following example shows blob input and output bindings in a function.json file and C# script (.csx) code that uses the bindings. The function makes a copy of a text blob. The function is triggered by a queue message that contains the name of the blob to copy. The new blob is named {originalblobname}-Copy.

In the function.json file, the queueTrigger metadata property is used to specify the blob name in the path properties:

{
  "bindings": [
    {
      "queueName": "myqueue-items",
      "connection": "MyStorageConnectionAppSetting",
      "name": "myQueueItem",
      "type": "queueTrigger",
      "direction": "in"
    },
    {
      "name": "myInputBlob",
      "type": "blob",
      "path": "samples-workitems/{queueTrigger}",
      "connection": "MyStorageConnectionAppSetting",
      "direction": "in"
    },
    {
      "name": "myOutputBlob",
      "type": "blob",
      "path": "samples-workitems/{queueTrigger}-Copy",
      "connection": "MyStorageConnectionAppSetting",
      "direction": "out"
    }
  ],
  "disabled": false
}

The configuration section explains these properties.

Here's the C# script code:

public static void Run(string myQueueItem, string myInputBlob, out string myOutputBlob, ILogger log)
{
    log.LogInformation($"C# Queue trigger function processed: {myQueueItem}");
    myOutputBlob = myInputBlob;
}

Input - JavaScript example

The following example shows blob input and output bindings in a function.json file and JavaScript code that uses the bindings. The function makes a copy of a blob. The function is triggered by a queue message that contains the name of the blob to copy. The new blob is named {originalblobname}-Copy.

In the function.json file, the queueTrigger metadata property is used to specify the blob name in the path properties:

{
  "bindings": [
    {
      "queueName": "myqueue-items",
      "connection": "MyStorageConnectionAppSetting",
      "name": "myQueueItem",
      "type": "queueTrigger",
      "direction": "in"
    },
    {
      "name": "myInputBlob",
      "type": "blob",
      "path": "samples-workitems/{queueTrigger}",
      "connection": "MyStorageConnectionAppSetting",
      "direction": "in"
    },
    {
      "name": "myOutputBlob",
      "type": "blob",
      "path": "samples-workitems/{queueTrigger}-Copy",
      "connection": "MyStorageConnectionAppSetting",
      "direction": "out"
    }
  ],
  "disabled": false
}

The configuration section explains these properties.

Here's the JavaScript code:

module.exports = function(context) {
    context.log('Node.js Queue trigger function processed', context.bindings.myQueueItem);
    context.bindings.myOutputBlob = context.bindings.myInputBlob;
    context.done();
};

Input - Python example

The following example shows blob input and output bindings in a function.json file and Python code that uses the bindings. The function makes a copy of a blob. The function is triggered by a queue message that contains the name of the blob to copy. The new blob is named {originalblobname}-Copy.

In the function.json file, the queueTrigger metadata property is used to specify the blob name in the path properties:

{
  "bindings": [
    {
      "queueName": "myqueue-items",
      "connection": "MyStorageConnectionAppSetting",
      "name": "queuemsg",
      "type": "queueTrigger",
      "direction": "in"
    },
    {
      "name": "inputblob",
      "type": "blob",
      "path": "samples-workitems/{queueTrigger}",
      "connection": "MyStorageConnectionAppSetting",
      "direction": "in"
    },
    {
      "name": "$return",
      "type": "blob",
      "path": "samples-workitems/{queueTrigger}-Copy",
      "connection": "MyStorageConnectionAppSetting",
      "direction": "out"
    }
  ],
  "disabled": false,
  "scriptFile": "__init__.py"
}

The configuration section explains these properties.

Here's the Python code:

import logging
import azure.functions as func


def main(queuemsg: func.QueueMessage, inputblob: func.InputStream) -> func.InputStream:
    logging.info('Python Queue trigger function processed %s', inputblob.name)
    return inputblob

Input - Java examples

This section contains the following examples:

HTTP trigger, look up blob name from query string (Java)

The following example shows a Java function that uses the HttpTrigger annotation to receive a parameter containing the name of a file in a blob storage container. The BlobInput annotation then reads the file and passes its contents to the function as a byte[].

  @FunctionName("getBlobSizeHttp")
  @StorageAccount("Storage_Account_Connection_String")
  public HttpResponseMessage blobSize(
    @HttpTrigger(name = "req", 
      methods = {HttpMethod.GET}, 
      authLevel = AuthorizationLevel.ANONYMOUS) 
    HttpRequestMessage<Optional<String>> request,
    @BlobInput(
      name = "file", 
      dataType = "binary", 
      path = "samples-workitems/{Query.file}") 
    byte[] content,
    final ExecutionContext context) {
      // build HTTP response with size of requested blob
      return request.createResponseBuilder(HttpStatus.OK)
        .body("The size of \"" + request.getQueryParameters().get("file") + "\" is: " + content.length + " bytes")
        .build();
  }

Queue trigger, receive blob name from queue message (Java)

The following example shows a Java function that uses the QueueTrigger annotation to receive a message containing the name of a file in a blob storage container. The BlobInput annotation then reads the file and passes its contents to the function as a byte[].

  @FunctionName("getBlobSize")
  @StorageAccount("Storage_Account_Connection_String")
  public void blobSize(
    @QueueTrigger(
      name = "filename", 
      queueName = "myqueue-items-sample") 
    String filename,
    @BlobInput(
      name = "file", 
      dataType = "binary", 
      path = "samples-workitems/{queueTrigger}") 
    byte[] content,
    final ExecutionContext context) {
      context.getLogger().info("The size of \"" + filename + "\" is: " + content.length + " bytes");
  }

In the Java functions runtime library, use the @BlobInput annotation on parameters whose value would come from a blob. This annotation can be used with native Java types, POJOs, or nullable values using Optional<T>.

Input - attributes

In C# class libraries, use the BlobAttribute.

The attribute's constructor takes the path to the blob and a FileAccess parameter indicating read or write, as shown in the following example:

[FunctionName("BlobInput")]
public static void Run(
    [QueueTrigger("myqueue-items")] string myQueueItem,
    [Blob("samples-workitems/{queueTrigger}", FileAccess.Read)] Stream myBlob,
    ILogger log)
{
    log.LogInformation($"BlobInput processed blob\n Name:{myQueueItem} \n Size: {myBlob.Length} bytes");
}

You can set the Connection property to specify the storage account to use, as shown in the following example:

[FunctionName("BlobInput")]
public static void Run(
    [QueueTrigger("myqueue-items")] string myQueueItem,
    [Blob("samples-workitems/{queueTrigger}", FileAccess.Read, Connection = "StorageConnectionAppSetting")] Stream myBlob,
    ILogger log)
{
    log.LogInformation($"BlobInput processed blob\n Name:{myQueueItem} \n Size: {myBlob.Length} bytes");
}

You can use the StorageAccount attribute to specify the storage account at class, method, or parameter level. For more information, see Trigger - attributes.

Input - configuration

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

function.json property Attribute property Description
type n/a Must be set to blob.
direction n/a Must be set to in. Exceptions are noted in the usage section.
name n/a The name of the variable that represents the blob in function code.
path BlobPath The path to the blob.
connection Connection The name of an app setting that contains the Storage connection string to use for this binding. If the app setting name begins with "AzureWebJobs", you can specify only the remainder of the name here. For example, if you set connection to "MyStorage", the Functions runtime looks for an app setting that is named "AzureWebJobsMyStorage." If you leave connection empty, the Functions runtime uses the default Storage connection string in the app setting that is named AzureWebJobsStorage.

The connection string must be for a general-purpose storage account, not a blob-only storage account.
n/a Access Indicates whether you will be reading or writing.

When you're developing locally, app settings go into the local.settings.json file.

Input - usage

In C# and C# script, you can use the following parameter types for the blob input binding:

  • Stream
  • TextReader
  • string
  • Byte[]
  • CloudBlobContainer
  • CloudBlobDirectory
  • ICloudBlob1
  • CloudBlockBlob1
  • CloudPageBlob1
  • CloudAppendBlob1

1 Requires "inout" binding direction in function.json or FileAccess.ReadWrite in a C# class library.

If you try to bind to one of the Storage SDK types and get an error message, make sure that you have a reference to the correct Storage SDK version.

Binding to string or Byte[] is only recommended if the blob size is small, as the entire blob contents are loaded into memory. Generally, it is preferable to use a Stream or CloudBlockBlob type. For more information, see Concurrency and memory usage earlier in this article.

In JavaScript, access the blob data using context.bindings.<name from function.json>.

Output

Use Blob storage output bindings to write blobs.

Output - example

See the language-specific example:

Output - C# example

The following example is a C# function that uses a blob trigger and two output blob bindings. The function is triggered by the creation of an image blob in the sample-images container. It creates small and medium size copies of the image blob.

using System.Collections.Generic;
using System.IO;
using Microsoft.Azure.WebJobs;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;

[FunctionName("ResizeImage")]
public static void Run(
    [BlobTrigger("sample-images/{name}")] Stream image,
    [Blob("sample-images-sm/{name}", FileAccess.Write)] Stream imageSmall,
    [Blob("sample-images-md/{name}", FileAccess.Write)] Stream imageMedium)
{
    IImageFormat format;

    using (Image<Rgba32> input = Image.Load(image, out format))
    {
      ResizeImage(input, imageSmall, ImageSize.Small, format);
    }

    image.Position = 0;
    using (Image<Rgba32> input = Image.Load(image, out format))
    {
      ResizeImage(input, imageMedium, ImageSize.Medium, format);
    }
}

public static void ResizeImage(Image<Rgba32> input, Stream output, ImageSize size, IImageFormat format)
{
    var dimensions = imageDimensionsTable[size];

    input.Mutate(x => x.Resize(dimensions.Item1, dimensions.Item2));
    input.Save(output, format);
}

public enum ImageSize { ExtraSmall, Small, Medium }

private static Dictionary<ImageSize, (int, int)> imageDimensionsTable = new Dictionary<ImageSize, (int, int)>() {
    { ImageSize.ExtraSmall, (320, 200) },
    { ImageSize.Small,      (640, 400) },
    { ImageSize.Medium,     (800, 600) }
};

Output - C# script example

The following example shows blob input and output bindings in a function.json file and C# script (.csx) code that uses the bindings. The function makes a copy of a text blob. The function is triggered by a queue message that contains the name of the blob to copy. The new blob is named {originalblobname}-Copy.

In the function.json file, the queueTrigger metadata property is used to specify the blob name in the path properties:

{
  "bindings": [
    {
      "queueName": "myqueue-items",
      "connection": "MyStorageConnectionAppSetting",
      "name": "myQueueItem",
      "type": "queueTrigger",
      "direction": "in"
    },
    {
      "name": "myInputBlob",
      "type": "blob",
      "path": "samples-workitems/{queueTrigger}",
      "connection": "MyStorageConnectionAppSetting",
      "direction": "in"
    },
    {
      "name": "myOutputBlob",
      "type": "blob",
      "path": "samples-workitems/{queueTrigger}-Copy",
      "connection": "MyStorageConnectionAppSetting",
      "direction": "out"
    }
  ],
  "disabled": false
}

The configuration section explains these properties.

Here's the C# script code:

public static void Run(string myQueueItem, string myInputBlob, out string myOutputBlob, ILogger log)
{
    log.LogInformation($"C# Queue trigger function processed: {myQueueItem}");
    myOutputBlob = myInputBlob;
}

Output - JavaScript example

The following example shows blob input and output bindings in a function.json file and JavaScript code that uses the bindings. The function makes a copy of a blob. The function is triggered by a queue message that contains the name of the blob to copy. The new blob is named {originalblobname}-Copy.

In the function.json file, the queueTrigger metadata property is used to specify the blob name in the path properties:

{
  "bindings": [
    {
      "queueName": "myqueue-items",
      "connection": "MyStorageConnectionAppSetting",
      "name": "myQueueItem",
      "type": "queueTrigger",
      "direction": "in"
    },
    {
      "name": "myInputBlob",
      "type": "blob",
      "path": "samples-workitems/{queueTrigger}",
      "connection": "MyStorageConnectionAppSetting",
      "direction": "in"
    },
    {
      "name": "myOutputBlob",
      "type": "blob",
      "path": "samples-workitems/{queueTrigger}-Copy",
      "connection": "MyStorageConnectionAppSetting",
      "direction": "out"
    }
  ],
  "disabled": false
}

The configuration section explains these properties.

Here's the JavaScript code:

module.exports = function(context) {
    context.log('Node.js Queue trigger function processed', context.bindings.myQueueItem);
    context.bindings.myOutputBlob = context.bindings.myInputBlob;
    context.done();
};

Output - Python example

The following example shows blob input and output bindings in a function.json file and Python code that uses the bindings. The function makes a copy of a blob. The function is triggered by a queue message that contains the name of the blob to copy. The new blob is named {originalblobname}-Copy.

In the function.json file, the queueTrigger metadata property is used to specify the blob name in the path properties:

{
  "bindings": [
    {
      "queueName": "myqueue-items",
      "connection": "MyStorageConnectionAppSetting",
      "name": "queuemsg",
      "type": "queueTrigger",
      "direction": "in"
    },
    {
      "name": "inputblob",
      "type": "blob",
      "path": "samples-workitems/{queueTrigger}",
      "connection": "MyStorageConnectionAppSetting",
      "direction": "in"
    },
    {
      "name": "outputblob",
      "type": "blob",
      "path": "samples-workitems/{queueTrigger}-Copy",
      "connection": "MyStorageConnectionAppSetting",
      "direction": "out"
    }
  ],
  "disabled": false,
  "scriptFile": "__init__.py"
}

The configuration section explains these properties.

Here's the Python code:

import logging
import azure.functions as func


def main(queuemsg: func.QueueMessage, inputblob: func.InputStream,
         outputblob: func.Out[func.InputStream]):
    logging.info('Python Queue trigger function processed %s', inputblob.name)
    outputblob.set(inputblob)

Output - Java examples

This section contains the following examples:

HTTP trigger, using OutputBinding (Java)

The following example shows a Java function that uses the HttpTrigger annotation to receive a parameter containing the name of a file in a blob storage container. The BlobInput annotation then reads the file and passes its contents to the function as a byte[]. The BlobOutput annotation binds to OutputBinding outputItem, which is then used by the function to write the contents of the input blob to the configured storage container.

  @FunctionName("copyBlobHttp")
  @StorageAccount("Storage_Account_Connection_String")
  public HttpResponseMessage copyBlobHttp(
    @HttpTrigger(name = "req", 
      methods = {HttpMethod.GET}, 
      authLevel = AuthorizationLevel.ANONYMOUS) 
    HttpRequestMessage<Optional<String>> request,
    @BlobInput(
      name = "file", 
      dataType = "binary", 
      path = "samples-workitems/{Query.file}") 
    byte[] content,
    @BlobOutput(
      name = "target", 
      path = "myblob/{Query.file}-CopyViaHttp")
    OutputBinding<String> outputItem,
    final ExecutionContext context) {
      // Save blob to outputItem
      outputItem.setValue(new String(content, StandardCharsets.UTF_8));

      // build HTTP response with size of requested blob
      return request.createResponseBuilder(HttpStatus.OK)
        .body("The size of \"" + request.getQueryParameters().get("file") + "\" is: " + content.length + " bytes")
        .build();
  }

Queue trigger, using function return value (Java)

The following example shows a Java function that uses the QueueTrigger annotation to receive a message containing the name of a file in a blob storage container. The BlobInput annotation then reads the file and passes its contents to the function as a byte[]. The BlobOutput annotation binds to the function return value, which is then used by the runtime to write the contents of the input blob to the configured storage container.

  @FunctionName("copyBlobQueueTrigger")
  @StorageAccount("Storage_Account_Connection_String")
  @BlobOutput(
    name = "target", 
    path = "myblob/{queueTrigger}-Copy")
  public String copyBlobQueue(
    @QueueTrigger(
      name = "filename", 
      dataType = "string",
      queueName = "myqueue-items") 
    String filename,
    @BlobInput(
      name = "file", 
      path = "samples-workitems/{queueTrigger}") 
    String content,
    final ExecutionContext context) {
      context.getLogger().info("The content of \"" + filename + "\" is: " + content);
      return content;
  }

In the Java functions runtime library, use the @BlobOutput annotation on function parameters whose value would be written to an object in blob storage. The parameter type should be OutputBinding<T>, where T is any native Java type or a POJO.

Output - attributes

In C# class libraries, use the BlobAttribute.

The attribute's constructor takes the path to the blob and a FileAccess parameter indicating read or write, as shown in the following example:

[FunctionName("ResizeImage")]
public static void Run(
    [BlobTrigger("sample-images/{name}")] Stream image,
    [Blob("sample-images-md/{name}", FileAccess.Write)] Stream imageSmall)
{
    ...
}

You can set the Connection property to specify the storage account to use, as shown in the following example:

[FunctionName("ResizeImage")]
public static void Run(
    [BlobTrigger("sample-images/{name}")] Stream image,
    [Blob("sample-images-md/{name}", FileAccess.Write, Connection = "StorageConnectionAppSetting")] Stream imageSmall)
{
    ...
}

For a complete example, see Output - C# example.

You can use the StorageAccount attribute to specify the storage account at class, method, or parameter level. For more information, see Trigger - attributes.

Output - configuration

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

function.json property Attribute property Description
type n/a Must be set to blob.
direction n/a Must be set to out for an output binding. Exceptions are noted in the usage section.
name n/a The name of the variable that represents the blob in function code. Set to $return to reference the function return value.
path BlobPath The path to the blob container.
connection Connection The name of an app setting that contains the Storage connection string to use for this binding. If the app setting name begins with "AzureWebJobs", you can specify only the remainder of the name here. For example, if you set connection to "MyStorage", the Functions runtime looks for an app setting that is named "AzureWebJobsMyStorage." If you leave connection empty, the Functions runtime uses the default Storage connection string in the app setting that is named AzureWebJobsStorage.

The connection string must be for a general-purpose storage account, not a blob-only storage account.
n/a Access Indicates whether you will be reading or writing.

When you're developing locally, app settings go into the local.settings.json file.

Output - usage

In C# and C# script, you can bind to the following types to write blobs:

  • TextWriter
  • out string
  • out Byte[]
  • CloudBlobStream
  • Stream
  • CloudBlobContainer1
  • CloudBlobDirectory
  • ICloudBlob2
  • CloudBlockBlob2
  • CloudPageBlob2
  • CloudAppendBlob2

1 Requires "in" binding direction in function.json or FileAccess.Read in a C# class library. However, you can use the container object that the runtime provides to do write operations, such as uploading blobs to the container.

2 Requires "inout" binding direction in function.json or FileAccess.ReadWrite in a C# class library.

If you try to bind to one of the Storage SDK types and get an error message, make sure that you have a reference to the correct Storage SDK version.

In async functions, use the return value or IAsyncCollector instead of an out parameter.

Binding to string or Byte[] is only recommended if the blob size is small, as the entire blob contents are loaded into memory. Generally, it is preferable to use a Stream or CloudBlockBlob type. For more information, see Concurrency and memory usage earlier in this article.

In JavaScript, access the blob data using context.bindings.<name from function.json>.

Exceptions and return codes

Binding Reference
Blob Blob Error Codes
Blob, Table, Queue Storage Error Codes
Blob, Table, Queue Troubleshooting

Next steps