F# Azure 函数的 Cosmos DB 绑定无法绑定

Cosmos DB bindings for F# Azure Function fails to bind

我正在尝试在 F# 中创建一个 Azure 函数,它具有 HTTP 触发器并从 Cosmos DB 检索数据。 documentation 仅在 C# 中提供 CosmosDB 绑定和翻译代码导致错误 Cannot bind parameter 'toDoItems' to type IEnumerable`1

的示例

此 C# 示例能够记录 Cosmos 中项目的 ID:

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;
using System.Collections.Generic;
using Microsoft.Extensions.Logging;

namespace Customer
{
    public class ToDoItem
    {
        public string Id { get; set; }
        public string PartitionKey { get; set; }
        public string Description { get; set; }
    }

    public static class DocByIdFromQueryString
    {
        [FunctionName("Triggered")]
        public static IActionResult Run(
            [HttpTrigger(
                AuthorizationLevel.Anonymous,
                "get",
                Route = null
            )] HttpRequest req,
            [CosmosDB(
                databaseName: "customer-db",
                collectionName: "todo-collection",
                ConnectionStringSetting = "CosmosDBConnection",
                SqlQuery = "select * from c"
            )] IEnumerable<ToDoItem> toDoItems, ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            foreach (ToDoItem toDoItem in toDoItems)
            {
                log.LogInformation(toDoItem.Id);
            }
            return new OkResult();
        }
    }
}

这是工作 C# 代码的 F# 翻译。这两个示例具有相同的依赖版本并使用相同的数据库(和连接字符串)。

namespace Customer

open Microsoft.AspNetCore.Http
open Microsoft.AspNetCore.Mvc
open Microsoft.Azure.WebJobs
open Microsoft.Azure.WebJobs.Extensions.Http
open Microsoft.Extensions.Logging


module CosmosBindings =
    type ToDoItem = {
        Id : string
        PartitionKey : string
        Description : string
    }

    [<FunctionName("HttpTrigger")>]
    let Run([<HttpTrigger(
                AuthorizationLevel.Anonymous,
                "get",
                Route = null
            )>] req: HttpRequest,
            [<CosmosDB(
                databaseName = "customer-db",
                collectionName = "todo-collection",
                ConnectionStringSetting = "CosmosDBConnection",
                SqlQuery = "select * from c"
            )>] toDoItems: ToDoItem seq) (log: ILogger) =
                log.LogInformation "F# HTTP trigger function processed a request."

                toDoItems
                |> Seq.iter (fun item -> log.LogInformation item.Id)

                OkObjectResult("Hello")

我试过在 function.json 文件中指定绑定,但无论在 bin/HttpTrigger/function.json 中添加什么,文件只包含 HttpTrigger(C# 和 F# ):

{
  "generatedBy": "Microsoft.NET.Sdk.Functions-3.0.1",
  "configurationSource": "attributes",
  "bindings": [
    {
      "type": "httpTrigger",
      "methods": [
        "get"
      ],
      "authLevel": "anonymous",
      "name": "req"
    }
  ],
  "disabled": false,
  "scriptFile": "../bin/Customer.dll",
  "entryPoint": "Customer.CosmosBindings.Run"
}

C# 和 F# 的依赖项和函数版本相同:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
    <AzureFunctionsVersion>v3</AzureFunctionsVersion>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.CosmosDB" Version="3.0.3" />
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.1" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="GetCustomer.fs" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
</Project>

来自 运行 F# 示例的错误:

[2/19/2020 4:01:52 PM] Starting JobHost
[2/19/2020 4:01:52 PM] Starting Host (HostId=havardandaestensenvippsnosmacboo, InstanceId=faf11b1c-b81d-49d2-8876-e4ef8785dc9f, Version=3.0.13107, ProcessId=30665, AppDomainId=1, InDebugMode=False, InDiagnosticMode=False, FunctionsExtensionVersion=(null))
[2/19/2020 4:01:52 PM] Loading functions metadata
[2/19/2020 4:01:52 PM] 1 functions loaded
[2/19/2020 4:01:52 PM] Generating 1 job function(s)
[2/19/2020 4:01:52 PM] Microsoft.Azure.WebJobs.Host: Error indexing method 'HttpTrigger'. Microsoft.Azure.WebJobs.Host: Cannot bind parameter 'toDoItems' to type IEnumerable`1. Make sure the parameter Type is supported by the binding. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).
[2/19/2020 4:01:52 PM] Error indexing method 'HttpTrigger'
[2/19/2020 4:01:52 PM] Microsoft.Azure.WebJobs.Host: Error indexing method 'HttpTrigger'. Microsoft.Azure.WebJobs.Host: Cannot bind parameter 'toDoItems' to type IEnumerable`1. Make sure the parameter Type is supported by the binding. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).
[2/19/2020 4:01:52 PM] Function 'HttpTrigger' failed indexing and will be disabled.
[2/19/2020 4:01:52 PM] No job functions found. Try making your job classes and methods public. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).
[2/19/2020 4:01:52 PM] Initializing function HTTP routes
[2/19/2020 4:01:52 PM] Mapped function route 'api/HttpTrigger' [get] to 'HttpTrigger'
[2/19/2020 4:01:52 PM]
[2/19/2020 4:01:52 PM] Host initialized (199ms)
[2/19/2020 4:01:52 PM] Host started (206ms)
[2/19/2020 4:01:52 PM] Job host started
[2/19/2020 4:01:52 PM] The 'HttpTrigger' function is in error: Microsoft.Azure.WebJobs.Host: Error indexing method 'HttpTrigger'. Microsoft.Azure.WebJobs.Host: Cannot bind parameter 'toDoItems' to type IEnumerable`1. Make sure the parameter Type is supported by the binding. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).

从 F# 代码中删除类型并仅从 CosmosDB 返回 toDoItems 也会导致错误。

[2/19/2020 4:22:33 PM] Generating 1 job function(s)
[2/19/2020 4:22:33 PM] No job functions found. Try making your job classes and methods public. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).
[2/19/2020 4:22:33 PM] Initializing function HTTP routes

关于 F# 和绑定的文档不多,但基于此:https://docs.microsoft.com/azure/azure-functions/functions-reference-fsharp#binding-to-arguments,看起来输出变量使用 byref<>,对于输入变量,类型需要用 [<CLIMutable>].

在这种情况下,作为 C# 中的 IEnumerable,我不确定是否需要 Seq.cast 而不是 seq

事实证明,用于生成函数的 F# 模板中存在错误。 an open issue 已经有将近一年的时间了,您必须为 host.jsonlocal.settings.json 使用 Include 而不是 Update。这是正确的 .fsproj 文件:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
    <AzureFunctionsVersion>v3</AzureFunctionsVersion>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.CosmosDB" Version="3.0.3" />
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.1" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="GetCustomer.fs" />
  </ItemGroup>
  <ItemGroup>
    <Content Include="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </Content>
  </ItemGroup>
</Project>

我很困惑为什么你必须指定输出变量的 return 类型。我相信不这样做是完全有效的 F#。并且错误消息对调试没有帮助:

[3/3/2020 11:57:09 AM] An unhandled host error has occurred.
[3/3/2020 11:57:09 AM] Microsoft.Azure.WebJobs.Host: 'HttpTrigger' can't be invoked from Azure WebJobs SDK. Is it missing Azure WebJobs SDK attributes?.

郑重声明,toDoItems: ToDoItem seqtoDoItems: IEnumerable<ToDoItem> 都产生相同的结果。