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

本文介绍了如何在 .NET 类库中使用 C# 开发 Azure Functions。

Azure Functions 支持 C# 和 C# 脚本编程语言。 如果要寻找有关在 Azure 门户中使用 C# 的指南,请参阅 C# 脚本 (.csx) 开发人员参考

本文假设你已阅读了以下文章:

Functions 类库项目

在 Visual Studio 中,Azure Functions 项目模板会创建一个 C# 类库项目,它包含以下文件:

  • host.json - 存储着在本地或者在 Azure 中运行时会影响项目中的所有函数的配置设置。
  • local.settings.json - 存储着在本地运行时使用的应用设置和连接字符串。 此文件包含机密且不会发布到 Azure 中的函数应用中。 必须向函数应用添加应用设置

生成项目时,在生成输出目录中生成如下所示的文件夹结构:

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

部署到 Azure 中函数应用的正是此目录。 Functions 运行时 2.x 版 中所需的绑定扩展作为 NuGet 包添加到项目中

Important

生成过程将为每个函数创建一个 function.json 文件。 此 function.json 文件不应直接编辑。 无法通过编辑此文件来更改绑定配置或禁用函数。 要了解如何禁用函数,请参阅如何禁用函数

识别为函数的方法

在类库中,函数是具有 FunctionName 和触发器属性的静态方法,如以下示例中所示:

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

FunctionName 属性将该方法标记为函数入口点。 该名称在项目中必须是唯一的,以字母开头,并且只包含字母、数字 _-,长度不得超过 127 个字符。 项目模板通常创建一个名为 Run 的方法,但方法名称可以是任何有效的 C# 方法名称。

触发器属性指定触发器类型并将输入数据绑定到一个方法参数。 示例函数将由一条队列消息触发,并且队列消息将传递到该方法中的 myQueueItem 参数。

方法签名参数

方法签名可能包含不与触发器属性一起使用的参数。 下面是可以包括的一些其他参数:

函数签名中的参数顺序并不重要。 例如,可以在其他绑定之前或之后放置触发器参数,也可以在触发器或绑定参数之前或之后添加记录器参数。

输出绑定示例

以下示例对上一个示例进行了修改,它添加了一个输出队列绑定。 该函数将触发函数的队列消息写入到另一个队列中的一条新队列消息。

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;
    }
}

绑定参考文章(例如,存储队列)说明了可用于触发器、输入或输出绑定特性的参数类型。

绑定表达式示例

以下代码从应用设置中获取要监视的队列的名称,并在 insertionTime 参数中获取队列消息创建时间。

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.json

生成过程会在生成文件中的一个函数文件夹中创建一个 function.json 文件。 如前所述,此文件不应直接编辑。 无法通过编辑此文件来更改绑定配置或禁用函数。

此文件的用途是向缩放控制器提供用于做出缩放决策的信息。 因此,此文件仅包含触发器信息,不包含输入或输出绑定。

生成的 function.json 文件包括一个 configurationSource 属性,该属性告诉运行时使用 .NET 属性进行绑定,而不是使用 function.json 配置。 下面是一个示例:

{
  "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.Functions

function.json 文件生成是由 NuGet 包 Microsoft.NET.Sdk.Functions 生成的。

Functions 运行时的 1.x 版本和 2.x 版本使用相同的包。 1.x 项目和 2.x 项目的不同之处在于目标框架。 以下是 csproj 文件的相关部分,其中显示了不同的目标框架和相同的 Sdk 包:

Functions 1.x

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

Functions 2.x

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

Sdk 包的依赖关系是触发器和绑定。 1.x 项目是指 1.x 触发器和绑定,因为它们面向 .NET Framework,而 2.x 触发器和绑定面向 .NET Core。

Sdk 包也依赖于 Newtonsoft.Json,并间接依赖于 WindowsAzure.Storage。 这些依赖关系确保项目使用的包版本与项目面向的 Functions 运行时版本兼容。 例如,Newtonsoft.Json 的 11 版可用于 .NET Framework 4.6.1,但面向 .NET Framework 4.6.1 的 Functions 运行时仅与 Newtonsoft.Json 9.0.1 兼容。 因此该项目中的函数代码也只能使用 Newtonsoft.Json 9.0.1。

GitHub 存储库 azure-functions-vs-build-sdk 中提供了适用于 Microsoft.NET.Sdk.Functions 的源代码。

运行时版本

Visual Studio 使用 Azure Functions Core Tools 运行 Functions 项目。 Core Tools 是适用于 Functions 运行时的命令行接口。

如果使用 npm 安装 Core Tools,则不会影响 Visual Studio 使用的 Core Tools 版本。 对于 Functions 运行时版本 1.x,Visual Studio 在 %USERPROFILE%\AppData\Local\Azure.Functions.Cli 中存储 Core Tools 版本且存储最新版本。 对于 Functions 2.x,Core Tools 包含在 Azure Functions 和 Web Jobs Tools 扩展中。 对于 1.x 和 2.x,运行 Functions 项目时可以看到控制台输出中正在使用何种版本:

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

绑定支持的类型

每个绑定都具有其自己支持的类型;例如,blob 触发器属性可以应用于字符串参数、POCO 参数、CloudBlockBlob 参数或任何其他几种受支持的类型之一。 适用于 blob 绑定的绑定参考文章列出了所有受支持的参数类型。 有关详细信息,请参阅触发器和绑定每个绑定类型的绑定参考文档

Tip

如果计划使用 HTTP 或 WebHook 绑定,请制定计划来避免因实例化 HttpClient 不当导致的端口耗尽现象。 有关详细信息,请参阅如何在 Azure Functions 中管理连接

绑定到方法返回值

通过将属性应用于方法返回值,可以对输出绑定使用方法返回值。 有关示例,请参阅触发器和绑定

仅当成功的函数执行始终将返回值传递给输出绑定时,才使用返回值。 否则,请使用 ICollectorIAsyncCollector,如以下部分所示。

写入多个输出值

若要将多个值写入输出绑定,或者如果成功的函数调用可能无法将任何内容传递给输出绑定,请使用 ICollectorIAsyncCollector 类型。 这些类型是只写集合,当方法完成时写入输出绑定。

此示例使用 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}");
    }
}

日志记录

若要使用 C# 将输出记录到流式处理日志中,请包括 ILogger 类型的参数。 建议将其命名为 log,如下例所示:

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

异步

要使函数异步,请使用 async 关键字并返回 Task 对象。

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 参数。 对于输出绑定,请改用函数返回值收集器对象

取消令牌

函数可以接受 CancellationToken 参数,以使操作系统能够在函数即将终止时通知代码。 可以使用此通知来确保该函数不会意外终止,导致数据处于不一致状态。

下面的示例演示了如何检查即将发生的函数终止。

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);
        }
    }
}

环境变量

若要获取环境变量或应用设置值,请使用 System.Environment.GetEnvironmentVariable,如以下代码示例所示:

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 中运行时,都可以从环境变量读取应用设置。 在本地开发时,应用设置来自 local.settings.json 文件中的 Values 集合。 在这两个环境(本地和 Azure)中,GetEnvironmentVariable("<app setting name>") 都会检索命名应用设置的值。 例如,在本地运行时,如果 local.settings.json 文件包含 { "Values": { "WEBSITE_SITE_NAME": "My Site Name" } },则会返回“My Site Name”。

System.Configuration.ConfigurationManager.AppSettings 属性是用于获取应用设置值的替代 API,但我们建议你使用 GetEnvironmentVariable,如下所示。

在运行时绑定

在 C# 和其他 .NET 语言中,可以使用命令性绑定模式,而不是在属性中使用“声明性”绑定 。 当绑定参数需要在运行时(而非在设计时)计算时,命令性绑定很有用。 通过此模式,可以在函数代码中动态绑定到受支持的输入和输出绑定。

如下所示定义命令性绑定:

  • 不要在函数签名中包括用于所需的命令性绑定的属性。

  • 传递输入参数 Binder binderIBinder binder

  • 使用下面的 C# 模式执行数据绑定。

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

    BindingTypeAttribute 是定义了绑定的 .NET 属性,T 是该绑定类型所支持的输入或输出类型。 T 不能是 out 参数类型(例如 out JObject)。 例如,移动应用表输出绑定支持六种输出类型,但对于命令性绑定,仅可使用 ICollectorIAsyncCollector

单属性示例

下面的示例代码使用在运行时定义的 blob 路径创建存储 blob 输出绑定,然后将字符串写入此 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 是支持的输出绑定类型。

多属性示例

上一个示例获取函数应用的主存储帐户连接字符串(即 AzureWebJobsStorage)的应用设置。 通过添加 StorageAccountAttribute 和将属性数组传入 BindAsync<T>(),可指定要用于存储帐户的自定义应用设置。 使用一个 Binder 参数而非 IBinder。 例如:

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!!");
        }
    }
}

触发器和绑定

下表显示了 Azure Functions 运行时的两个主要版本支持的绑定。

类型 1.x 2.x1 触发器 输入 输出
Blob 存储
Cosmos DB
事件中心
HTTP 和 Webhook
Microsoft Graph
Excel 表
Microsoft Graph
OneDrive 文件
Microsoft Graph
Outlook 电子邮件
Microsoft Graph
事件
Microsoft Graph
身份验证令牌
移动应用
通知中心
队列存储
SendGrid
服务总线
表存储
计时器

1 在 2.x 中,除了 HTTP 和 Timer 以外,所有绑定都必须注册。 请参阅注册绑定扩展

后续步骤