Develop Azure Functions using Visual Studio

Visual Studio lets you develop, test, and deploy C# class library functions to Azure. If this experience is your first with Azure Functions, you can learn more at An introduction to Azure Functions.

Visual Studio provides the following benefits when develop your functions:

  • Edit, build, and run functions on your local development computer.
  • Publish your Azure Functions project directly to Azure, and create Azure resources as needed.
  • Use C# attributes to declare function bindings directly in the C# code.
  • Develop and deploy pre-compiled C# functions. Pre-complied functions provide a better cold-start performance than C# script-based functions.
  • Code your functions in C# while having all of the benefits of Visual Studio development.

This article provides details about how to use Visual Studio to develop C# class library functions and publish them to Azure. Before you read this article, you should complete the Functions quickstart for Visual Studio.

Unless otherwise noted, procedures and examples shown are for Visual Studio 2019.

Prerequisites

Azure Functions Tools is included in the Azure development workload of Visual Studio starting with Visual Studio 2017. Make sure you include the Azure development workload in your Visual Studio installation.

If you don't have an Azure subscription, create a free account before you begin.

Other resources that you need, such as an Azure Storage account, are created in your subscription during the publishing process.

Note

In Visual Studio 2017, the Azure development workload installs the Azure Functions Tools as a separate extension. When you update your Visual Studio 2017, also make sure that you are using the most recent version of the Azure Functions tools. The following sections show you how to check and (if needed) update your Azure Functions Tools extension in Visual Studio 2017.

Please skip these section when using Visual Studio 2019.

Check your tools version in Visual Studio 2017

  1. From the Tools menu, choose Extensions and Updates. Expand Installed > Tools and choose Azure Functions and Web Jobs Tools.

    Verify the Functions tools version

  2. Note the installed Version. You can compare this version with the latest version listed in the release notes.

  3. If your version is older, update your tools in Visual Studio as shown in the following section.

Update your tools in Visual Studio 2017

  1. In the Extensions and Updates dialog, expand Updates > Visual Studio Marketplace, choose Azure Functions and Web Jobs Tools and select Update.

    Update the Functions tools version

  2. After the tools update is downloaded, close Visual Studio to trigger the tools update using the VSIX installer.

  3. In the installer, choose OK to start and then Modify to update the tools.

  4. After the update is complete, choose Close and restart Visual Studio.

Note

In Visual Studio 2019 and later, the Azure Functions tools extension is updated as part of Visual Studio.

Create an Azure Functions project

The Azure Functions project template in Visual Studio creates a project that can be published to a function app in Azure. You can use a function app to group functions as a logical unit for management, deployment, and sharing of resources.

  1. In Visual Studio, on the File menu, select New > Project.

  2. In the Create a new project dialog box, search for functions, choose the Azure Functions template, and select Next.

  3. Enter a name for your project, and select Create. The function app name must be valid as a C# namespace, so don't use underscores, hyphens, or any other nonalphanumeric characters.

  4. In Create a new Azure Functions application, use the following options:

    • Azure Functions v2 (.NET Core) 1
    • HTTP trigger
    • Storage Account: Storage Emulator
    • Authorization level: Anonymous
    Option Suggested value Description
    Functions runtime Azure Functions 2.x
    (.NET Core)
    This setting creates a function project that uses the version 2.x runtime of Azure Functions, which supports .NET Core. Azure Functions 1.x supports the .NET Framework. For more information, see Target Azure Functions runtime version.
    Function template HTTP trigger This setting creates a function triggered by an HTTP request.
    Storage Account Storage Emulator An HTTP trigger doesn't use the Azure Storage account connection. All other trigger types require a valid Storage account connection string. Because Functions requires a storage account, one is assigned or created when you publish your project to Azure.
    Authorization level Anonymous The created function can be triggered by any client without providing a key. This authorization setting makes it easy to test your new function. For more information about keys and authorization, see Authorization keys in the HTTP and webhook bindings.

    Note

    Make sure you set the Authorization level to Anonymous. If you choose the default level of Function, you're required to present the function key in requests to access your function endpoint.

  5. Select Create to create the function project and HTTP-triggered function.

The project template creates a C# project, installs the Microsoft.NET.Sdk.Functions NuGet package, and sets the target framework. The new project has the following files:

  • host.json: Lets you configure the Functions host. These settings apply both when running locally and in Azure. For more information, see host.json reference.

  • local.settings.json: Maintains settings used when running functions locally. These settings aren't used when running in Azure. For more information, see Local settings file.

    Important

    Because the local.settings.json file can contain secrets, you must excluded it from your project source control. The Copy to Output Directory setting for this file should always be Copy if newer.

For more information, see Functions class library project.

Local settings file

The local.settings.json file stores app settings, connection strings, and settings used by local development tools. Settings in the local.settings.json file are used only when you're running projects locally. The local settings file has this structure:

{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "<language worker>",
    "AzureWebJobsStorage": "<connection-string>",
    "AzureWebJobsDashboard": "<connection-string>",
    "MyBindingConnection": "<binding-connection-string>"
  },
  "Host": {
    "LocalHttpPort": 7071,
    "CORS": "*",
    "CORSCredentials": false
  },
  "ConnectionStrings": {
    "SQLConnectionString": "<sqlclient-connection-string>"
  }
}

These settings are supported when you run projects locally:

Setting Description
IsEncrypted When this setting is set to true, all values are encrypted with a local machine key. Used with func settings commands. Default value is false.
Values Array of application settings and connection strings used when a project is running locally. These key-value (string-string) pairs correspond to application settings in your function app in Azure, like AzureWebJobsStorage. Many triggers and bindings have a property that refers to a connection string app setting, like Connection for the Blob storage trigger. For these properties, you need an application setting defined in the Values array.
AzureWebJobsStorage is a required app setting for triggers other than HTTP.
Version 2.x of the Functions runtime requires the [FUNCTIONS_WORKER_RUNTIME] setting, which is generated for your project by Core Tools.
When you have the Azure storage emulator installed locally and you set AzureWebJobsStorage to UseDevelopmentStorage=true, Core Tools uses the emulator. The emulator is useful during development, but you should test with an actual storage connection before deployment.
Values must be strings and not JSON objects or arrays. Setting names can't include a colon (:) or a double underline (__). These characters are reserved by the runtime.
Host Settings in this section customize the Functions host process when you run projects locally. These settings are separate from the host.json settings, which also apply when you run projects in Azure.
LocalHttpPort Sets the default port used when running the local Functions host (func host start and func run). The --port command-line option takes precedence over this setting.
CORS Defines the origins allowed for cross-origin resource sharing (CORS). Origins are supplied as a comma-separated list with no spaces. The wildcard value (*) is supported, which allows requests from any origin.
CORSCredentials When set to true, allows withCredentials requests.
ConnectionStrings A collection. Don't use this collection for the connection strings used by your function bindings. This collection is used only by frameworks that typically get connection strings from the ConnectionStrings section of a configuration file, like Entity Framework. Connection strings in this object are added to the environment with the provider type of System.Data.SqlClient. Items in this collection aren't published to Azure with other app settings. You must explicitly add these values to the Connection strings collection of your function app settings. If you're creating a SqlConnection in your function code, you should store the connection string value with your other connections in Application Settings in the portal.

Settings in local.settings.json aren't uploaded automatically when you publish the project. To make sure that these settings also exist in your function app in Azure, you must upload them after you publish your project. To learn more, see Function app settings.

Values in ConnectionStrings are never published.

The function app settings values can also be read in your code as environment variables. For more information, see Environment variables.

Configure the project for local development

The Functions runtime uses an Azure Storage account internally. For all trigger types other than HTTP and webhooks, you must set the Values.AzureWebJobsStorage key to a valid Azure Storage account connection string. Your function app can also use the Azure storage emulator for the AzureWebJobsStorage connection setting that is required by the project. To use the emulator, set the value of AzureWebJobsStorage to UseDevelopmentStorage=true. Change this setting to an actual storage account connection string before deployment.

To set the storage account connection string:

  1. In Visual Studio, open Cloud Explorer, expand Storage Account > Your Storage Account, then in the Properties tab copy the Primary Connection String value.

  2. In your project, open the local.settings.json file and set the value of the AzureWebJobsStorage key to the connection string you copied.

  3. Repeat the previous step to add unique keys to the Values array for any other connections required by your functions.

Add a function to your project

In C# class library functions, the bindings used by the function are defined by applying attributes in the code. When you create your function triggers from the provided templates, the trigger attributes are applied for you.

  1. In Solution Explorer, right-click on your project node and select Add > New Item. Select Azure Function, type a Name for the class, and click Add.

  2. Choose your trigger, set the binding properties, and click Create. The following example shows the settings when creating a Queue storage triggered function.

    Create a queue triggered function

    This trigger example uses a connection string with a key named QueueStorage. This connection string setting must be defined in the local.settings.json file.

  3. Examine the newly added class. You see a static Run method, that is attributed with the FunctionName attribute. This attribute indicates that the method is the entry point for the function.

    For example, the following C# class represents a basic Queue storage triggered function:

    using System;
    using Microsoft.Azure.WebJobs;
    using Microsoft.Azure.WebJobs.Host;
    using Microsoft.Extensions.Logging;
    
    namespace FunctionApp1
    {
        public static class Function1
        {
            [FunctionName("QueueTriggerCSharp")]
            public static void Run([QueueTrigger("myqueue-items", 
                Connection = "QueueStorage")]string myQueueItem, ILogger log)
            {
                log.LogInformation($"C# Queue trigger function processed: {myQueueItem}");
            }
        }
    }
    

    A binding-specific attribute is applied to each binding parameter supplied to the entry point method. The attribute takes the binding information as parameters. In the previous example, the first parameter has a QueueTrigger attribute applied, indicating queue triggered function. The queue name and connection string setting name are passed as parameters to the QueueTrigger attribute. For more information, see Azure Queue storage bindings for Azure Functions.

You can use the above procedure to add more functions to your function app project. Each function in the project can have a different trigger, but a function must have exactly one trigger. For more information, see Azure Functions triggers and bindings concepts.

Add bindings

As with triggers, input and output bindings are added to your function as binding attributes. Add bindings to a function as follows:

  1. Make sure you've configured the project for local development.

  2. Add the appropriate NuGet extension package for the specific binding. For more information, see Local C# development using Visual Studio in the Triggers and Bindings article. The binding-specific NuGet package requirements are found in the reference article for the binding. For example, find package requirements for the Event Hubs trigger in the Event Hubs binding reference article.

  3. If there are app settings that the binding needs, add them to the Values collection in the local setting file. These values are used when the function runs locally. When the function runs in the function app in Azure, the function app settings are used.

  4. Add the appropriate binding attribute to the method signature. In the following example, a queue message triggers the function, and the output binding creates a new queue message with the same text in a different queue.

    public static class SimpleExampleWithOutput
    {
        [FunctionName("CopyQueueMessage")]
        public static void Run(
            [QueueTrigger("myqueue-items-source", Connection = "AzureWebJobsStorage")] string myQueueItem, 
            [Queue("myqueue-items-destination", Connection = "AzureWebJobsStorage")] out string myQueueItemCopy,
            ILogger log)
        {
            log.LogInformation($"CopyQueueMessage function processed: {myQueueItem}");
            myQueueItemCopy = myQueueItem;
        }
    }
    

    The connection to Queue storage is obtained from the AzureWebJobsStorage setting. For more information, see the reference article for the specific binding.

This table shows the bindings that are supported in the two major versions of the Azure Functions runtime:

Type 1.x 2.x1 Trigger Input Output
Blob storage
Cosmos DB
Event Grid
Event Hubs
HTTP & webhooks
IoT Hub
Microsoft Graph
Excel tables
Microsoft Graph
OneDrive files
Microsoft Graph
Outlook email
Microsoft Graph
events
Microsoft Graph
Auth tokens
Mobile Apps
Notification Hubs
Queue storage
SendGrid
Service Bus
SignalR
Table storage
Timer
Twilio

1 In 2.x, all bindings except HTTP and Timer must be registered. See Register binding extensions.

Testing functions

Azure Functions Core Tools lets you run Azure Functions project on your local development computer. You are prompted to install these tools the first time you start a function from Visual Studio.

To test your function, press F5. If prompted, accept the request from Visual Studio to download and install Azure Functions Core (CLI) tools. You may also need to enable a firewall exception so that the tools can handle HTTP requests.

With the project running, you can test your code as you would test deployed function. For more information, see Strategies for testing your code in Azure Functions. When running in debug mode, breakpoints are hit in Visual Studio as expected.

To learn more about using the Azure Functions Core Tools, see Code and test Azure functions locally.

Publish to Azure

When publishing from Visual Studio, one of two deployment methods are used:

Use the following steps to publish your project to a function app in Azure.

  1. In Solution Explorer, right-click the project and select Publish.

  2. In the Pick a publish target dialog, use the publish options as specified in the table below the image:

    Pick a publish target

    Option Description
    Azure Functions Consumption plan When you publish your project to a function app that runs in a Consumption plan, you only pay for executions of your functions app. Other hosting plans incur higher costs. To learn more, see Azure Functions scale and hosting.
    Create new A new function app, with related resources, is created in Azure. When you choose Select Existing, all files in the existing function app in Azure are overwritten by files from the local project. Only use this option when republishing updates to an existing function app.
    Run from package file Your function app is deployed using Zip Deploy with Run-From-Package mode enabled. This is the recommended way of running your functions, which results in better performance. When not using this option, make sure to stop your function app project from running locally before you publish to Azure.
  3. Select Publish. If you haven't already signed-in to your Azure account from Visual Studio, select Sign-in. You can also create a free Azure account.

  4. In the App Service: Create new dialog, use the Hosting settings as specified in the table below the image:

    Create App Service dialog

    Setting Suggested value Description
    Name Globally unique name Name that uniquely identifies your new function app. Valid characters are a-z, 0-9, and -.
    Subscription Choose your subscription The Azure subscription to use.
    Resource Group myResourceGroup Name of the resource group in which to create your function app. Choose New to create a new resource group.
    Hosting Plan Consumption plan Make sure to choose the Consumption under Size after you select New to create a serverless plan. Also, choose a Location in a region near you or near other services your functions access. When you run in a plan other than Consumption, you must manage the scaling of your function app.
    Azure Storage General-purpose storage account An Azure storage account is required by the Functions runtime. Select New to create a general-purpose storage account. You can also use an existing account that meets the storage account requirements.
  5. Select Create to create a function app and related resources in Azure with these settings and deploy your function project code.

  6. After the deployment is complete, make a note of the Site URL value, which is the address of your function app in Azure.

    Publish success message

Function app settings

Any settings you added in the local.settings.json must be also added to the function app in Azure. These settings aren't uploaded automatically when you publish the project.

The easiest way to upload the required settings to your function app in Azure is to use the Manage Application Settings... link that is displayed after you successfully publish your project.

This displays the Application Settings dialog for the function app, where you can add new application settings or modify existing ones.

Local represents a setting value in the local.settings.json file, and Remote is the current setting in the function app in Azure. Choose Add setting to create a new app setting. Use the Insert value from Local link to copy a setting value to the Remote field. Pending changes are written to the local settings file and the function app when you select OK.

Note

By default, the local.settings.json file is not checked into source control. This means that when you clone a local Functions project from source control, the project doesn't have a local.settings.json file. In this case, you need to manually create the local.settings.json file in the project root so that the Application Settings dialog works as expected.

You can also manage application settings in one of these other ways:

Monitoring functions

The recommended way to monitor the execution of your functions is by integrating your function app with Azure Application Insights. When you create a function app in the Azure portal, this integration is done for you by default. However, when you create your function app during Visual Studio publishing, the integration in your function app in Azure isn't done.

To enable Application Insights for your function app:

Functions makes it easy to add Application Insights integration to a function app from the Azure portal.

  1. In the portal, select All services > Function Apps, select your function app, and then select the Application Insights banner at the top of the window

    Enable Application Insights from the portal

  2. Create an Application Insights resource by using the settings specified in the table below the image.

    Create an Application Insights resource

    Setting Suggested value Description
    Name Unique app name It's easiest to use the same name as your function app, which must be unique in your subscription.
    Location West Europe If possible, use the same region as your function app, or one that's close to that region.
  3. Select OK. The Application Insights resource is created in the same resource group and subscription as your function app. After the resource is created, close the Application Insights window.

  4. Back in your function app, select Application settings, and then scroll down to Application settings. If you see a setting named APPINSIGHTS_INSTRUMENTATIONKEY, Application Insights integration is enabled for your function app running in Azure.

To learn more, see Monitor Azure Functions.

Next steps

To learn more about the Azure Functions Core Tools, see Code and test Azure functions locally.

To learn more about developing functions as .NET class libraries, see Azure Functions C# developer reference. This article also links to examples of how to use attributes to declare the various types of bindings supported by Azure Functions.