Azure Functions C# developer reference(Azure Functions C# 开发人员参考)Azure Functions C# developer reference

本文介绍了如何在 .NET 类库中使用 C# 开发 Azure Functions。This article is an introduction to developing Azure Functions by using C# in .NET class libraries.

Azure Functions 支持 C# 和 C# 脚本编程语言。Azure Functions supports C# and C# script programming languages. 如果要寻找有关在 Azure 门户中使用 C# 的指南,请参阅 C# 脚本 (.csx) 开发人员参考If you're looking for guidance on using C# in the Azure portal, see C# script (.csx) developer reference.

本文假设你已阅读了以下文章:This article assumes that you've already read the following articles:

Functions 类库项目Functions class library project

在 Visual Studio 中,Azure Functions 项目模板会创建一个 C# 类库项目,它包含以下文件:In Visual Studio, the Azure Functions project template creates a C# class library project that contains the following files:

  • host.json - 存储着在本地或者在 Azure 中运行时会影响项目中的所有函数的配置设置。host.json - stores configuration settings that affect all functions in the project when running locally or in Azure.
  • local.settings.json - 存储着在本地运行时使用的应用设置和连接字符串。local.settings.json - stores app settings and connection strings that are used when running locally. 此文件包含机密且不会发布到 Azure 中的函数应用中。This file contains secrets and isn't published to your function app in Azure. 必须向函数应用添加应用设置You must instead add app settings to your function app.

生成项目时,在生成输出目录中生成如下所示的文件夹结构:When you build the project, a folder structure that looks like the following is generated in the build output directory:

<framework.version>
 | - bin
 | - MyFirstFunction
 | | - function.json
 | - MySecondFunction
 | | - function.json
 | - host.json

部署到 Azure 中函数应用的正是此目录。This directory is what gets deployed to your function app in Azure. Functions 运行时 2.x 版 中所需的绑定扩展作为 NuGet 包添加到项目中The binding extensions required in version 2.x of the Functions runtime are added to the project as NuGet packages.

Important

生成过程将为每个函数创建一个 function.json 文件。The build process creates a function.json file for each function. function.json 文件不应直接编辑。This function.json file is not meant to be edited directly. 无法通过编辑此文件来更改绑定配置或禁用函数。You can't change binding configuration or disable the function by editing this file. 要了解如何禁用函数,请参阅如何禁用函数To learn how to disable a function, see How to disable functions.

识别为函数的方法Methods recognized as functions

在类库中,函数是具有 FunctionName 和触发器属性的静态方法,如以下示例中所示:In a class library, a function is a static method with a FunctionName and a trigger attribute, as shown in the following example:

public static class SimpleExample
{
    [FunctionName("QueueTrigger")]
    public static void Run(
        [QueueTrigger("myqueue-items")] string myQueueItem, 
        ILogger log)
    {
        log.LogInformation($"C# function processed: {myQueueItem}");
    }
} 

FunctionName 属性将该方法标记为函数入口点。The FunctionName attribute marks the method as a function entry point. 该名称在项目中必须是唯一的,以字母开头,并且只包含字母、数字 _-,长度不得超过 127 个字符。The name must be unique within a project, start with a letter and only contain letters, numbers, _ and -, up to 127 characters in length. 项目模板通常创建一个名为 Run 的方法,但方法名称可以是任何有效的 C# 方法名称。Project templates often create a method named Run, but the method name can be any valid C# method name.

触发器属性指定触发器类型并将输入数据绑定到一个方法参数。The trigger attribute specifies the trigger type and binds input data to a method parameter. 示例函数将由一条队列消息触发,并且队列消息将传递到该方法中的 myQueueItem 参数。The example function is triggered by a queue message, and the queue message is passed to the method in the myQueueItem parameter.

方法签名参数Method signature parameters

方法签名可能包含不与触发器属性一起使用的参数。The method signature may contain parameters other than the one used with the trigger attribute. 下面是可以包括的一些其他参数:Here are some of the additional parameters that you can include:

函数签名中的参数顺序并不重要。The order of parameters in the function signature does not matter. 例如,可以在其他绑定之前或之后放置触发器参数,也可以在触发器或绑定参数之前或之后添加记录器参数。For example, you can put trigger parameters before or after other bindings, and you can put the logger parameter before or after trigger or binding parameters.

输出绑定示例Output binding example

以下示例对上一个示例进行了修改,它添加了一个输出队列绑定。The following example modifies the preceding one by adding an output queue binding. 该函数将触发函数的队列消息写入到另一个队列中的一条新队列消息。The function writes the queue message that triggers the function to a new queue message in a different queue.

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

绑定参考文章(例如,存储队列)说明了可用于触发器、输入或输出绑定特性的参数类型。The binding reference articles (Storage queues, for example) explain which parameter types you can use with trigger, input, or output binding attributes.

绑定表达式示例Binding expressions example

以下代码从应用设置中获取要监视的队列的名称,并在 insertionTime 参数中获取队列消息创建时间。The following code gets the name of the queue to monitor from an app setting, and it gets the queue message creation time in the insertionTime parameter.

public static class BindingExpressionsExample
{
    [FunctionName("LogQueueMessage")]
    public static void Run(
        [QueueTrigger("%queueappsetting%")] string myQueueItem,
        DateTimeOffset insertionTime,
        ILogger log)
    {
        log.LogInformation($"Message content: {myQueueItem}");
        log.LogInformation($"Created at: {insertionTime}");
    }
}

自动生成的 function.jsonAutogenerated function.json

生成过程会在生成文件中的一个函数文件夹中创建一个 function.json 文件。The build process creates a function.json file in a function folder in the build folder. 如前所述,此文件不应直接编辑。As noted earlier, this file is not meant to be edited directly. 无法通过编辑此文件来更改绑定配置或禁用函数。You can't change binding configuration or disable the function by editing this file.

此文件的用途是向缩放控制器提供用于对消耗计划做出缩放决策的信息。The purpose of this file is to provide information to the scale controller to use for scaling decisions on the consumption plan. 因此,此文件仅包含触发器信息,不包含输入或输出绑定。For this reason, the file only has trigger info, not input or output bindings.

生成的 function.json 文件包括一个 configurationSource 属性,该属性告诉运行时使用 .NET 属性进行绑定,而不是使用 function.json 配置。The generated function.json file includes a configurationSource property that tells the runtime to use .NET attributes for bindings, rather than function.json configuration. 下面是一个示例:Here's an example:

{
  "generatedBy": "Microsoft.NET.Sdk.Functions-1.0.0.0",
  "configurationSource": "attributes",
  "bindings": [
    {
      "type": "queueTrigger",
      "queueName": "%input-queue-name%",
      "name": "myQueueItem"
    }
  ],
  "disabled": false,
  "scriptFile": "..\\bin\\FunctionApp1.dll",
  "entryPoint": "FunctionApp1.QueueTrigger.Run"
}

Microsoft.NET.Sdk.FunctionsMicrosoft.NET.Sdk.Functions

function.json 文件生成是由 NuGet 包 Microsoft.NET.Sdk.Functions 生成的。The function.json file generation is performed by the NuGet package Microsoft.NET.Sdk.Functions.

Functions 运行时的 1.x 版本和 2.x 版本使用相同的包。The same package is used for both version 1.x and 2.x of the Functions runtime. 1.x 项目和 2.x 项目的不同之处在于目标框架。The target framework is what differentiates a 1.x project from a 2.x project. 以下是 csproj 文件的相关部分,其中显示了不同的目标框架和相同的 Sdk 包:Here are the relevant parts of .csproj files, showing different target frameworks and the same Sdk package:

Functions 1.xFunctions 1.x

<PropertyGroup>
  <TargetFramework>net461</TargetFramework>
</PropertyGroup>
<ItemGroup>
  <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.8" />
</ItemGroup>

Functions 2.xFunctions 2.x

<PropertyGroup>
  <TargetFramework>netcoreapp2.1</TargetFramework>
  <AzureFunctionsVersion>v2</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
  <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.8" />
</ItemGroup>

Sdk 包的依赖关系是触发器和绑定。Among the Sdk package dependencies are triggers and bindings. 1.x 项目是指 1.x 触发器和绑定,因为它们面向 .NET Framework,而 2.x 触发器和绑定面向 .NET Core。A 1.x project refers to 1.x triggers and bindings because those target the .NET Framework, while 2.x triggers and bindings target .NET Core.

Sdk 包也依赖于 Newtonsoft.Json,并间接依赖于 WindowsAzure.StorageThe Sdk package also depends on Newtonsoft.Json, and indirectly on WindowsAzure.Storage. 这些依赖关系确保项目使用的包版本与项目面向的 Functions 运行时版本兼容。These dependencies make sure that your project uses the versions of those packages that work with the Functions runtime version that the project targets. 例如,Newtonsoft.Json 的 11 版可用于 .NET Framework 4.6.1,但面向 .NET Framework 4.6.1 的 Functions 运行时仅与 Newtonsoft.Json 9.0.1 兼容。For example, Newtonsoft.Json has version 11 for .NET Framework 4.6.1, but the Functions runtime that targets .NET Framework 4.6.1 is only compatible with Newtonsoft.Json 9.0.1. 因此该项目中的函数代码也只能使用 Newtonsoft.Json 9.0.1。So your function code in that project also has to use Newtonsoft.Json 9.0.1.

GitHub 存储库 azure-functions-vs-build-sdk 中提供了适用于 Microsoft.NET.Sdk.Functions 的源代码。The source code for Microsoft.NET.Sdk.Functions is available in the GitHub repo azure-functions-vs-build-sdk.

运行时版本Runtime version

Visual Studio 使用 Azure Functions Core Tools 运行 Functions 项目。Visual Studio uses the Azure Functions Core Tools to run Functions projects. Core Tools 是适用于 Functions 运行时的命令行接口。The Core Tools is a command-line interface for the Functions runtime.

如果使用 npm 安装 Core Tools,则不会影响 Visual Studio 使用的 Core Tools 版本。If you install the Core Tools by using npm, that doesn't affect the Core Tools version used by Visual Studio. 对于 Functions 运行时版本 1.x,Visual Studio 在 %USERPROFILE%\AppData\Local\Azure.Functions.Cli 中存储 Core Tools 版本且存储最新版本。For the Functions runtime version 1.x, Visual Studio stores Core Tools versions in %USERPROFILE%\AppData\Local\Azure.Functions.Cli and uses the latest version stored there. 对于 Functions 2.x,Core Tools 包含在 Azure Functions 和 Web Jobs Tools 扩展中。For Functions 2.x, the Core Tools are included in the Azure Functions and Web Jobs Tools extension. 对于 1.x 和 2.x,运行 Functions 项目时可以看到控制台输出中正在使用何种版本:For both 1.x and 2.x, you can see what version is being used in the console output when you run a Functions project:

[3/1/2018 9:59:53 AM] Starting Host (HostId=contoso2-1518597420, Version=2.0.11353.0, ProcessId=22020, Debug=False, Attempt=0, FunctionsExtensionVersion=)

绑定支持的类型Supported types for bindings

每个绑定都具有其自己支持的类型;例如,blob 触发器属性可以应用于字符串参数、POCO 参数、CloudBlockBlob 参数或任何其他几种受支持的类型之一。Each binding has its own supported types; for instance, a blob trigger attribute can be applied to a string parameter, a POCO parameter, a CloudBlockBlob parameter, or any of several other supported types. 适用于 blob 绑定的绑定参考文章列出了所有受支持的参数类型。The binding reference article for blob bindings lists all supported parameter types. 有关详细信息,请参阅触发器和绑定每个绑定类型的绑定参考文档For more information, see Triggers and bindings and the binding reference docs for each binding type.

Tip

如果计划使用 HTTP 或 WebHook 绑定,请制定计划来避免因实例化 HttpClient 不当导致的端口耗尽现象。If you plan to use the HTTP or WebHook bindings, plan to avoid port exhaustion that can be caused by improper instantiation of HttpClient. 有关详细信息,请参阅如何在 Azure Functions 中管理连接For more information, see How to manage connections in Azure Functions.

绑定到方法返回值Binding to method return value

通过将属性应用于方法返回值,可以对输出绑定使用方法返回值。You can use a method return value for an output binding, by applying the attribute to the method return value. 有关示例,请参阅触发器和绑定For examples, see Triggers and bindings.

仅当成功的函数执行始终将返回值传递给输出绑定时,才使用返回值。Use the return value only if a successful function execution always results in a return value to pass to the output binding. 否则,请使用 ICollectorIAsyncCollector,如以下部分所示。Otherwise, use ICollector or IAsyncCollector, as shown in the following section.

写入多个输出值Writing multiple output values

若要将多个值写入输出绑定,或者如果成功的函数调用可能无法将任何内容传递给输出绑定,请使用 ICollectorIAsyncCollector 类型。To write multiple values to an output binding, or if a successful function invocation might not result in anything to pass to the output binding, use the ICollector or IAsyncCollector types. 这些类型是只写集合,当方法完成时写入输出绑定。These types are write-only collections that are written to the output binding when the method completes.

此示例使用 ICollector 将多个队列消息写入到同一队列:This example writes multiple queue messages into the same queue using ICollector:

public static class ICollectorExample
{
    [FunctionName("CopyQueueMessageICollector")]
    public static void Run(
        [QueueTrigger("myqueue-items-source-3")] string myQueueItem,
        [Queue("myqueue-items-destination")] ICollector<string> myDestinationQueue,
        ILogger log)
    {
        log.LogInformation($"C# function processed: {myQueueItem}");
        myDestinationQueue.Add($"Copy 1: {myQueueItem}");
        myDestinationQueue.Add($"Copy 2: {myQueueItem}");
    }
}

日志记录Logging

若要使用 C# 将输出记录到流式传输日志中,请包括 ILogger 类型的参数。To log output to your streaming logs in C#, include an argument of type ILogger. 建议将其命名为 log,如下例所示:We recommend that you name it log, as in the following example:

public static class SimpleExample
{
    [FunctionName("QueueTrigger")]
    public static void Run(
        [QueueTrigger("myqueue-items")] string myQueueItem, 
        ILogger log)
    {
        log.LogInformation($"C# function processed: {myQueueItem}");
    }
} 

异步Async

要使函数异步,请使用 async 关键字并返回 Task 对象。To make a function asynchronous, use the async keyword and return a Task object.

public static class AsyncExample
{
    [FunctionName("BlobCopy")]
    public static async Task RunAsync(
        [BlobTrigger("sample-images/{blobName}")] Stream blobInput,
        [Blob("sample-images-copies/{blobName}", FileAccess.Write)] Stream blobOutput,
        CancellationToken token,
        ILogger log)
    {
        log.LogInformation($"BlobCopy function processed.");
        await blobInput.CopyToAsync(blobOutput, 4096, token);
    }
}

不能在异步函数中使用 out 参数。You can't use out parameters in async functions. 对于输出绑定,请改用函数返回值收集器对象For output bindings, use the function return value or a collector object instead.

取消令牌Cancellation tokens

函数可以接受 CancellationToken 参数,以使操作系统能够在函数即将终止时通知代码。A function can accept a CancellationToken parameter, which enables the operating system to notify your code when the function is about to be terminated. 可以使用此通知来确保该函数不会意外终止,导致数据处于不一致状态。You can use this notification to make sure the function doesn't terminate unexpectedly in a way that leaves data in an inconsistent state.

下面的示例演示了如何检查即将发生的函数终止。The following example shows how to check for impending function termination.

public static class CancellationTokenExample
{
    public static void Run(
        [QueueTrigger("inputqueue")] string inputText,
        TextWriter logger,
        CancellationToken token)
    {
        for (int i = 0; i < 100; i++)
        {
            if (token.IsCancellationRequested)
            {
                logger.WriteLine("Function was cancelled at iteration {0}", i);
                break;
            }
            Thread.Sleep(5000);
            logger.WriteLine("Normal processing for queue message={0}", inputText);
        }
    }
}

环境变量Environment variables

若要获取环境变量或应用设置值,请使用 System.Environment.GetEnvironmentVariable,如以下代码示例所示:To get an environment variable or an app setting value, use System.Environment.GetEnvironmentVariable, as shown in the following code example:

public static class EnvironmentVariablesExample
{
    [FunctionName("GetEnvironmentVariables")]
    public static void Run([TimerTrigger("0 */5 * * * *")]TimerInfo myTimer, ILogger log)
    {
        log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
        log.LogInformation(GetEnvironmentVariable("AzureWebJobsStorage"));
        log.LogInformation(GetEnvironmentVariable("WEBSITE_SITE_NAME"));
    }

    public static string GetEnvironmentVariable(string name)
    {
        return name + ": " +
            System.Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Process);
    }
}

在本地开发和在 Azure 中运行时,都可以从环境变量读取应用设置。App settings can be read from environment variables both when developing locally and when running in Azure. 在本地开发时,应用设置来自 local.settings.json 文件中的 Values 集合。When developing locally, app settings come from the Values collection in the local.settings.json file. 在这两个环境(本地和 Azure)中,GetEnvironmentVariable("<app setting name>") 都会检索命名应用设置的值。In both environments, local and Azure, GetEnvironmentVariable("<app setting name>") retrieves the value of the named app setting. 例如,在本地运行时,如果 local.settings.json 文件包含 { "Values": { "WEBSITE_SITE_NAME": "My Site Name" } },则会返回“My Site Name”。For instance, when you're running locally, "My Site Name" would be returned if your local.settings.json file contains { "Values": { "WEBSITE_SITE_NAME": "My Site Name" } }.

System.Configuration.ConfigurationManager.AppSettings 属性是用于获取应用设置值的替代 API,但我们建议你使用 GetEnvironmentVariable,如下所示。The System.Configuration.ConfigurationManager.AppSettings property is an alternative API for getting app setting values, but we recommend that you use GetEnvironmentVariable as shown here.

在运行时绑定Binding at runtime

在 C# 和其他 .NET 语言中,可以使用命令性绑定模式,而不是在属性中使用“声明性”绑定In C# and other .NET languages, you can use an imperative binding pattern, as opposed to the declarative bindings in attributes. 当绑定参数需要在运行时(而非在设计时)计算时,命令性绑定很有用。Imperative binding is useful when binding parameters need to be computed at runtime rather than design time. 通过此模式,可以在函数代码中动态绑定到受支持的输入和输出绑定。With this pattern, you can bind to supported input and output bindings on-the-fly in your function code.

如下所示定义命令性绑定:Define an imperative binding as follows:

  • 不要在函数签名中包括用于所需的命令性绑定的属性。Do not include an attribute in the function signature for your desired imperative bindings.

  • 传递输入参数 Binder binderIBinder binderPass in an input parameter Binder binder or IBinder binder.

  • 使用下面的 C# 模式执行数据绑定。Use the following C# pattern to perform the data binding.

    using (var output = await binder.BindAsync<T>(new BindingTypeAttribute(...)))
    {
        ...
    }
    

    BindingTypeAttribute 是定义了绑定的 .NET 属性,T 是该绑定类型所支持的输入或输出类型。BindingTypeAttribute is the .NET attribute that defines your binding, and T is an input or output type that's supported by that binding type. T 不能是 out 参数类型(例如 out JObject)。T cannot be an out parameter type (such as out JObject). 例如,移动应用表输出绑定支持六种输出类型,但对于命令性绑定,仅可使用 ICollectorIAsyncCollectorFor example, the Mobile Apps table output binding supports six output types, but you can only use ICollector or IAsyncCollector with imperative binding.

单属性示例Single attribute example

下面的示例代码使用在运行时定义的 blob 路径创建存储 blob 输出绑定,然后将字符串写入此 blob。The following example code creates a Storage blob output binding with blob path that's defined at run time, then writes a string to the blob.

public static class IBinderExample
{
    [FunctionName("CreateBlobUsingBinder")]
    public static void Run(
        [QueueTrigger("myqueue-items-source-4")] string myQueueItem,
        IBinder binder,
        ILogger log)
    {
        log.LogInformation($"CreateBlobUsingBinder function processed: {myQueueItem}");
        using (var writer = binder.Bind<TextWriter>(new BlobAttribute(
                    $"samples-output/{myQueueItem}", FileAccess.Write)))
        {
            writer.Write("Hello World!");
        };
    }
}

BlobAttribute 定义存储 Blob 输入或输出绑定,TextWriter 是支持的输出绑定类型。BlobAttribute defines the Storage blob input or output binding, and TextWriter is a supported output binding type.

多属性示例Multiple attribute example

上一个示例获取函数应用的主存储帐户连接字符串(即 AzureWebJobsStorage)的应用设置。The preceding example gets the app setting for the function app's main Storage account connection string (which is AzureWebJobsStorage). 通过添加 StorageAccountAttribute 和将属性数组传入 BindAsync<T>(),可指定要用于存储帐户的自定义应用设置。You can specify a custom app setting to use for the Storage account by adding the StorageAccountAttribute and passing the attribute array into BindAsync<T>(). 使用一个 Binder 参数而非 IBinderUse a Binder parameter, not IBinder. 例如:For example:

public static class IBinderExampleMultipleAttributes
{
    [FunctionName("CreateBlobInDifferentStorageAccount")]
    public async static Task RunAsync(
            [QueueTrigger("myqueue-items-source-binder2")] string myQueueItem,
            Binder binder,
            ILogger log)
    {
        log.LogInformation($"CreateBlobInDifferentStorageAccount function processed: {myQueueItem}");
        var attributes = new Attribute[]
        {
        new BlobAttribute($"samples-output/{myQueueItem}", FileAccess.Write),
        new StorageAccountAttribute("MyStorageAccount")
        };
        using (var writer = await binder.BindAsync<TextWriter>(attributes))
        {
            await writer.WriteAsync("Hello World!!");
        }
    }
}

触发器和绑定Triggers and bindings

下表显示了 Azure Functions 运行时的两个主要版本支持的绑定。The following table shows the bindings that are supported in the two major versions of the Azure Functions runtime.

类型Type 1.x1.x 2.x12.x1 触发器Trigger 输入Input 输出Output
Blob 存储Blob Storage
Cosmos DBCosmos DB
事件中心Event Hubs
HTTP 和 WebhookHTTP & Webhooks
Microsoft Graph
Excel 表
Microsoft Graph
Excel tables
Microsoft Graph
OneDrive 文件
Microsoft Graph
OneDrive files
Microsoft Graph
Outlook 电子邮件
Microsoft Graph
Outlook email
Microsoft Graph
事件
Microsoft Graph
Events
Microsoft Graph
身份验证令牌
Microsoft Graph
Auth tokens
移动应用Mobile Apps
通知中心Notification Hubs
队列存储Queue storage
SendGridSendGrid
服务总线Service Bus
表存储Table storage
计时器Timer

1 在 2.x 中,除了 HTTP 和 Timer 以外,所有绑定都必须注册。1 In 2.x, all bindings except HTTP and Timer must be registered. 请参阅注册绑定扩展See Register binding extensions.

后续步骤Next steps