适用于 Azure Functions 的 Azure 表输出绑定

使用 Azure 表输出绑定将实体写入 Azure 存储或 Azure Cosmos DB 帐户中的表。

有关设置和配置的详细信息,请参阅概述

注意

此输出绑定仅支持在表中创建新实体。 如果需要从函数代码更新现有实体,请改为直接使用 Azure 表 SDK。

示例

可以使用以下 C# 模式之一创建 C# 函数:

  • 进程内类库:编译的 C# 函数,该函数在与 Functions 运行时相同的进程中运行。
  • 独立进程类库:编译的 C# 函数,该函数在独立于运行时的进程中运行。 支持在 .NET 5.0 上运行的 C# 函数需要独立的进程。
  • C# 脚本:主要在 Azure 门户中创建 C# 函数时使用。

以下示例演示使用 HTTP 触发器写入单个表行的 C# 函数

public class TableStorage
{
    public class MyPoco
    {
        public string PartitionKey { get; set; }
        public string RowKey { get; set; }
        public string Text { get; set; }
    }

    [FunctionName("TableOutput")]
    [return: Table("MyTable")]
    public static MyPoco TableOutput([HttpTrigger] dynamic input, ILogger log)
    {
        log.LogInformation($"C# http trigger function processed: {input.Text}");
        return new MyPoco { PartitionKey = "Http", RowKey = Guid.NewGuid().ToString(), Text = input.Text };
    }
}

以下示例演示了使用 HTTP 触发器写入单个表行的 Java 函数。

public class Person {
    private String PartitionKey;
    private String RowKey;
    private String Name;

    public String getPartitionKey() {return this.PartitionKey;}
    public void setPartitionKey(String key) {this.PartitionKey = key; }
    public String getRowKey() {return this.RowKey;}
    public void setRowKey(String key) {this.RowKey = key; }
    public String getName() {return this.Name;}
    public void setName(String name) {this.Name = name; }
}

public class AddPerson {

    @FunctionName("addPerson")
    public HttpResponseMessage get(
            @HttpTrigger(name = "postPerson", methods = {HttpMethod.POST}, authLevel = AuthorizationLevel.FUNCTION, route="persons/{partitionKey}/{rowKey}") HttpRequestMessage<Optional<Person>> request,
            @BindingName("partitionKey") String partitionKey,
            @BindingName("rowKey") String rowKey,
            @TableOutput(name="person", partitionKey="{partitionKey}", rowKey = "{rowKey}", tableName="%MyTableName%", connection="MyConnectionString") OutputBinding<Person> person,
            final ExecutionContext context) {

        Person outPerson = new Person();
        outPerson.setPartitionKey(partitionKey);
        outPerson.setRowKey(rowKey);
        outPerson.setName(request.getBody().get().getName());

        person.setValue(outPerson);

        return request.createResponseBuilder(HttpStatus.OK)
                        .header("Content-Type", "application/json")
                        .body(outPerson)
                        .build();
    }
}

以下示例演示了使用 HTTP 触发器写入多个表行的 Java 函数。

public class Person {
    private String PartitionKey;
    private String RowKey;
    private String Name;

    public String getPartitionKey() {return this.PartitionKey;}
    public void setPartitionKey(String key) {this.PartitionKey = key; }
    public String getRowKey() {return this.RowKey;}
    public void setRowKey(String key) {this.RowKey = key; }
    public String getName() {return this.Name;}
    public void setName(String name) {this.Name = name; }
}

public class AddPersons {

    @FunctionName("addPersons")
    public HttpResponseMessage get(
            @HttpTrigger(name = "postPersons", methods = {HttpMethod.POST}, authLevel = AuthorizationLevel.FUNCTION, route="persons/") HttpRequestMessage<Optional<Person[]>> request,
            @TableOutput(name="person", tableName="%MyTableName%", connection="MyConnectionString") OutputBinding<Person[]> persons,
            final ExecutionContext context) {

        persons.setValue(request.getBody().get());

        return request.createResponseBuilder(HttpStatus.OK)
                        .header("Content-Type", "application/json")
                        .body(request.getBody().get())
                        .build();
    }
}

以下示例演示 function.json 文件中的一个表输出绑定以及使用该绑定的 JavaScript 函数。 该函数写入多个表实体。

function.json 文件如下所示:

{
  "bindings": [
    {
      "name": "input",
      "type": "manualTrigger",
      "direction": "in"
    },
    {
      "tableName": "Person",
      "connection": "MyStorageConnectionAppSetting",
      "name": "tableBinding",
      "type": "table",
      "direction": "out"
    }
  ],
  "disabled": false
}

配置部分解释了这些属性。

JavaScript 代码如下所示:

module.exports = async function (context) {

    context.bindings.tableBinding = [];

    for (var i = 1; i < 10; i++) {
        context.bindings.tableBinding.push({
            PartitionKey: "Test",
            RowKey: i.toString(),
            Name: "Name " + i
        });
    }
};

以下示例演示如何通过一个函数向表中写入多个实体。

function.json 中的绑定配置:

{
  "bindings": [
    {
      "name": "InputData",
      "type": "manualTrigger",
      "direction": "in"
    },
    {
      "tableName": "Person",
      "connection": "MyStorageConnectionAppSetting",
      "name": "TableBinding",
      "type": "table",
      "direction": "out"
    }
  ],
  "disabled": false
}

run.ps1 中的 PowerShell 代码:

param($InputData, $TriggerMetadata)

foreach ($i in 1..10) {
    Push-OutputBinding -Name TableBinding -Value @{
        PartitionKey = 'Test'
        RowKey = "$i"
        Name = "Name $i"
    }
}

下面的示例演示如何使用表存储输出绑定。 通过为 nametableNamepartitionKeyconnection 分配值,在 function.json 中配置 table 绑定:

{
  "scriptFile": "__init__.py",
  "bindings": [
    {
      "name": "message",
      "type": "table",
      "tableName": "messages",
      "partitionKey": "message",
      "connection": "AzureWebJobsStorage",
      "direction": "out"
    },
    {
      "authLevel": "function",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": [
        "get",
        "post"
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    }
  ]
}

以下函数为 rowKey 值生成唯一 UUI,并将消息持久保存在表存储中。

import logging
import uuid
import json

import azure.functions as func

def main(req: func.HttpRequest, message: func.Out[str]) -> func.HttpResponse:

    rowKey = str(uuid.uuid4())

    data = {
        "Name": "Output binding message",
        "PartitionKey": "message",
        "RowKey": rowKey
    }

    message.set(json.dumps(data))

    return func.HttpResponse(f"Message created with the rowKey: {rowKey}")

特性

进程内独立进程 C# 库使用特性来定义函数。 C# 脚本改为使用 function.json 配置文件。

C# 类库中,TableAttribute 支持以下属性:

Attribute 属性 说明
TableName 要向其写入的表的名称。
PartitionKey 要写入的表实体的分区键。
RowKey 要写入的表实体的行键。
Connection 指定如何连接到表服务的应用设置或设置集合的名称。 请参阅连接

该特性的构造函数采用表名称。 对 out 参数或函数的返回值使用该特性,如以下示例中所示:

[FunctionName("TableOutput")]
[return: Table("MyTable")]
public static MyPoco TableOutput(
    [HttpTrigger] dynamic input, 
    ILogger log)
{
    ...
}

可以设置 Connection 属性以指定与表服务的连接,如以下示例中所示:

[FunctionName("TableOutput")]
[return: Table("MyTable", Connection = "StorageConnectionAppSetting")]
public static MyPoco TableOutput(
    [HttpTrigger] dynamic input, 
    ILogger log)
{
    ...
}

尽管该特性采用 Connection 属性,但你也可以使用 StorageAccountAttribute 来指定存储帐户连接。 如果需要使用一个不同于库中的其他函数的存储帐户,可以执行此操作。 构造函数采用包含存储连接字符串的应用设置的名称。 可以在参数、方法或类级别应用该特性。 以下示例演示类级别和方法级别:

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

要使用的存储帐户按以下顺序确定:

  • 触发器或绑定特性的 Connection 属性。
  • 作为触发器或绑定特性应用到同一参数的 StorageAccount 特性。
  • 应用到函数的 StorageAccount 特性。
  • 应用到类的 StorageAccount 特性。
  • 函数应用的默认存储帐户,在 AzureWebJobsStorage 应用程序设置中定义。

批注

Java 函数运行时库中,对参数使用 TableOutput 注释以将值写入到表中。 该特性支持以下元素:

元素 说明
name 在函数代码中使用的、表示表或实体的变量名称。
dataType 定义 Functions 运行时应如何处理参数值。 有关详细信息,请参阅 dataType
tableName 要向其写入的表的名称。
partitionKey 要写入的表实体的分区键。
rowKey 要写入的表实体的行键。
连接 指定如何连接到表服务的应用设置或设置集合的名称。 请参阅连接

配置

下表解释了在 function.json 文件中设置的绑定配置属性。

function.json 属性 说明
type 必须设置为 table。 在 Azure 门户中创建绑定时,会自动设置此属性。
direction 必须设置为 out。 在 Azure 门户中创建绑定时,会自动设置此属性。
name 在函数代码中使用的、表示表或实体的变量名称。 设置为 $return 可引用函数返回值。
tableName 要向其写入的表的名称。
partitionKey 要写入的表实体的分区键。
rowKey 要写入的表实体的行键。
连接 指定如何连接到表服务的应用设置或设置集合的名称。 请参阅连接

在本地开发时,请将应用程序设置添加到 Values 集合的 local.settings.json 文件

连接

connection 属性是对环境配置的引用,它指定应用应该如何连接到表服务。 它可能指定:

如果配置的值既是单个设置的完全匹配,也是其他设置的前缀匹配,则使用完全匹配。

连接字符串

若要在 Azure 表存储中为表获取连接字符串,请执行管理存储帐户访问密钥中显示的步骤。 若要在 Azure Cosmos DB for Table 中为表获取连接字符串,请执行 Azure Cosmos DB for Table 常见问题解答中显示的步骤。

此连接字符串应存储在应用程序设置中,其名称与绑定配置的 connection 属性指定的值匹配。

如果应用设置名称以“AzureWebJobs”开始,则只能在此处指定该名称的余下部分。 例如,如果将 connection 设置为“MyStorage”,则 Functions 运行时会查找名为“AzureWebJobsMyStorage”的应用设置。 如果将 connection 留空,函数运行时将使用名为 AzureWebJobsStorage 的应用设置中的默认存储连接字符串。

基于标识的连接

如果使用表 API 扩展,则无需将连接字符串与机密一起使用,而是可以使应用使用 Azure Active Directory 标识。 这仅适用于访问 Azure 存储中的表的情况。 为此,需要定义公共前缀下的设置,该前缀映射到触发器和绑定配置中的 connection 属性。

如果将 connection 设置为“AzureWebJobsStorage”,请参阅使用标识连接到主机存储。 对于所有其他连接,扩展需要以下属性:

属性 环境变量模板 说明 示例值
表服务 URI <CONNECTION_NAME_PREFIX>__tableServiceUri1 要连接到的 Azure 存储表服务的数据平面 URI,使用 HTTPS 方案。 https://<storage_account_name>.table.core.chinacloudapi.cn

1<CONNECTION_NAME_PREFIX>__serviceUri 可以用作别名。 如果同时提供了两个窗体,则将使用 tableServiceUri 窗体。 如果跨 Blob、队列和/或表使用总体连接配置,则无法使用 serviceUri 窗体。

可以设置其他属性来自定义连接。 请参阅基于标识的连接的通用属性

如果要在 Azure 存储中跨 Blob、队列和/或表使用总体连接配置,则无法使用 serviceUri 窗体。 URI 本身只能指定表服务。 作为一种替代方案,可以在同一前缀下为每个服务专门提供一个 URI,从而允许使用单个连接。

在 Azure Functions 服务中托管时,基于标识的连接将使用托管标识。 默认情况下使用系统分配的标识,但可以使用 credentialclientID 属性来指定用户分配的标识。 请注意,不支持为用户分配的标识配置资源 ID。 在其他上下文(如本地开发)中运行时,将改用开发人员标识,尽管可以进行自定义。 请参阅使用基于标识的连接进行本地开发

向标识授予权限

无论使用何种标识,都必须具有执行所需操作的权限。 需要使用内置角色或者提供这些权限的自定义角色在 Azure RBAC 中分配角色

重要

某些权限可能由并非所有上下文都需要的目标服务公开。 尽可能遵循最低权限原则,仅授予标识所需的权限。 例如,如果应用只需要从数据源进行读取即可,则使用仅具有读取权限的角色。 分配一个也具有该服务写入权限的角色并不恰当,因为对于读取操作来说,写入是多余的权限。 同样,你也希望确保角色分配的范围仅限于需要读取的资源。

你将需要创建一个角色分配,以便在运行时提供对 Azure 存储表服务的访问权限。 所有者等管理角色还不够。 下表显示了在正常操作中对 Azure 存储使用 Azure Cosmos DB for Table 扩展时建议使用的内置角色。 根据所编写的代码,应用程序可能需要具有其他权限。

绑定类型 内置角色示例(Azure 存储1
输入绑定 存储表数据读取者
输出绑定 存储表数据参与者

1 如果应用改为连接到 Azure Cosmos DB for Table 中的表,则不支持使用标识,并且连接必须使用连接字符串。

使用情况

绑定的用法取决于扩展包版本,以及函数应用中使用的 C# 形式,可以是以下形式之一:

进程内类库是编译的 C# 函数,该函数在与 Functions 运行时相同的进程中运行。

选择一个版本以查看模式和版本的使用情况详细信息。

out 参数和返回类型支持以下类型:

  • 包含 PartitionKeyRowKey 属性的普通旧 CLR 对象 (POCO)。 可以通过实现 ITableEntity 或继承 TableEntity 来随附这些属性。
  • ICollector<T>IAsyncCollector<T>,其中 T 包括 PartitionKeyRowKey 属性。 可以通过实现 ITableEntity 或继承 TableEntity 来随附这些属性。

还可以作为方法参数从存储 SDK 绑定到 CloudTable。 然后,可以使用该对象写入到表。

有两个选项可用于使用 TableStorageOutput 注释从函数来输出表存储行:

选项 描述
返回值 通过将注释应用于函数本身,函数的返回值将持久保存为表存储行。
命令性 若要显式设置表行,请将注释应用于 OutputBinding<T> 类型的特定参数,其中 T 包括 PartitionKeyRowKey 属性。 可以通过实现 ITableEntity 或继承 TableEntity 来随附这些属性。

使用 context.bindings.<name> 访问输出事件,其中 <name> 是 function.json 的 name 属性中指定的值。

若要写入到表数据,请使用 Push-OutputBinding cmdlet,将 -Name TableBinding 参数和 -Value 参数设置为等于行数据。 有关更多详细信息,请参阅 PowerShell 示例

有两个选项可用于从函数输出表存储行消息:

选项 描述
返回值 将 function.json 中的 name 属性 设置为 $return。 使用此配置时,函数的返回值将作为表存储行保留。
命令性 将值传递给声明为 Out 类型的参数的 set 方法。 传递给 set 的值将保留为表行。

有关特定使用情况的详细信息,请参阅示例

异常和返回代码

绑定 参考
表错误代码
Blob、表、队列 存储错误代码
Blob、表、队列 故障排除

后续步骤