Azure Functions v2 中 ILogger 的 F# 错误
F# errors with ILogger in Azure Functions v2
我有一个相当大的项目,其中包含用 F# 编写的 Azure Function v2。我在 C# 中创建了一个库,在构造函数中我可以传递 ILogger log
。如果我只在 Azure Function 项目中添加这个库,每个函数 returns 都会出错。
Microsoft.Azure.WebJobs.Host: Cannot bind parameter 'log' to type ILogger. Make sure the parameter Type is supported by the binding
在 F# 中我尝试添加
[<FunctionName("organization")>]
let public organization
( [<HttpTrigger(AuthorizationLevel.Function, "post", Route = "organisations/{organisationId}")>]
request : HttpRequestMessage,
organisationId : string,
executionContext : ExecutionContext,
log : ILogger) =
let PaymentGateway = PaymentGateway(Environment.GetEnvironmentVariable "Api_Secret_Key", log)
...
我在 GitHub or another post 上看到一些帖子,其他人也有同样的问题。显然,解决方案是将 Azure 函数从 v2 更新到 v3,但我现在不能这样做。
有什么解决办法吗?
更新
.fsproj
是
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AzureFunctionsVersion>v2</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<Content Include="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="4.6.2" />
</ItemGroup>
</Project>
不管怎样,你的fs确实有问题。我把可以成功触发的函数文件和代码贴在这里:
这是我的函数应用程序的结构:
这是我的 .fsproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AzureFunctionsVersion>v3</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<Compile Include="HttpTrigger.fs" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.3" />
</ItemGroup>
<ItemGroup>
<Content Include="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</Content>
</ItemGroup>
</Project>
这是我的触发文件HttpTrigger.fs:
namespace Company.Function
open System
open System.IO
open Microsoft.AspNetCore.Mvc
open Microsoft.Azure.WebJobs
open Microsoft.Azure.WebJobs.Extensions.Http
open Microsoft.AspNetCore.Http
open Newtonsoft.Json
open Microsoft.Extensions.Logging
module HttpTrigger =
// Define a nullable container to deserialize into.
[<AllowNullLiteral>]
type NameContainer() =
member val Name = "" with get, set
// For convenience, it's better to have a central place for the literal.
[<Literal>]
let Name = "name"
[<FunctionName("HttpTrigger")>]
let run ([<HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)>]req: HttpRequest) (log: ILogger) =
async {
log.LogInformation("F# HTTP trigger function processed a request.")
let nameOpt =
if req.Query.ContainsKey(Name) then
Some(req.Query.[Name].[0])
else
None
use stream = new StreamReader(req.Body)
let! reqBody = stream.ReadToEndAsync() |> Async.AwaitTask
let data = JsonConvert.DeserializeObject<NameContainer>(reqBody)
let name =
match nameOpt with
| Some n -> n
| None ->
match data with
| null -> ""
| nc -> nc.Name
let responseMessage =
if (String.IsNullOrWhiteSpace(name)) then
"This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
else
"Hello, " + name + ". This HTTP triggered function executed successfully."
return OkObjectResult(responseMessage) :> IActionResult
} |> Async.StartAsTask
工作正常,成功日志:
这是我创建 运行 F# 函数的步骤:
1.Runcmd中的这两条命令:
dotnet new --install Microsoft.Azure.WebJobs.ItemTemplates
dotnet new --install Microsoft.Azure.WebJobs.ProjectTemplates
2.Create 函数应用:
dotnet new func --language F# --name FunctionsInFSharp
3.Create 触发器:
dotnet new http --language F# --name HttpTrigger
4.Add 触发编译:
<Compile Include="HttpTrigger.fs" />
请将以上代码添加到 .fsproj 文件中的 ItemGroup。
5.Change 模板,将这些从 none 更改为内容:
我给出的只是一个简单的F#函数触发成功的例子,请试一试,看能不能解决。:)
经过一周的测试和更改,我找到了一个不理想的解决方案,但它正在运行。
在函数中我这样定义 logInfo:
let logInfo : Action<string> = new Action<string>(fun (x: string) -> log.LogInformation(x))
在我的 C# 库中,我删除了对 Microsoft.Extensions.Logging
的所有引用,并将其替换为:
private Action<string> _logger;
public PaymentGateway(string apiKey, Action<string> logger) {
_logger = logger;
}
至少,我的组件中有日志。我不喜欢这个解决方案,但这是我可以用 F# 做的。
我有一个相当大的项目,其中包含用 F# 编写的 Azure Function v2。我在 C# 中创建了一个库,在构造函数中我可以传递 ILogger log
。如果我只在 Azure Function 项目中添加这个库,每个函数 returns 都会出错。
Microsoft.Azure.WebJobs.Host: Cannot bind parameter 'log' to type ILogger. Make sure the parameter Type is supported by the binding
在 F# 中我尝试添加
[<FunctionName("organization")>]
let public organization
( [<HttpTrigger(AuthorizationLevel.Function, "post", Route = "organisations/{organisationId}")>]
request : HttpRequestMessage,
organisationId : string,
executionContext : ExecutionContext,
log : ILogger) =
let PaymentGateway = PaymentGateway(Environment.GetEnvironmentVariable "Api_Secret_Key", log)
...
我在 GitHub or another post 上看到一些帖子,其他人也有同样的问题。显然,解决方案是将 Azure 函数从 v2 更新到 v3,但我现在不能这样做。
有什么解决办法吗?
更新
.fsproj
是
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AzureFunctionsVersion>v2</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<Content Include="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="4.6.2" />
</ItemGroup>
</Project>
不管怎样,你的fs确实有问题。我把可以成功触发的函数文件和代码贴在这里:
这是我的函数应用程序的结构:
这是我的 .fsproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AzureFunctionsVersion>v3</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<Compile Include="HttpTrigger.fs" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.3" />
</ItemGroup>
<ItemGroup>
<Content Include="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</Content>
</ItemGroup>
</Project>
这是我的触发文件HttpTrigger.fs:
namespace Company.Function
open System
open System.IO
open Microsoft.AspNetCore.Mvc
open Microsoft.Azure.WebJobs
open Microsoft.Azure.WebJobs.Extensions.Http
open Microsoft.AspNetCore.Http
open Newtonsoft.Json
open Microsoft.Extensions.Logging
module HttpTrigger =
// Define a nullable container to deserialize into.
[<AllowNullLiteral>]
type NameContainer() =
member val Name = "" with get, set
// For convenience, it's better to have a central place for the literal.
[<Literal>]
let Name = "name"
[<FunctionName("HttpTrigger")>]
let run ([<HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)>]req: HttpRequest) (log: ILogger) =
async {
log.LogInformation("F# HTTP trigger function processed a request.")
let nameOpt =
if req.Query.ContainsKey(Name) then
Some(req.Query.[Name].[0])
else
None
use stream = new StreamReader(req.Body)
let! reqBody = stream.ReadToEndAsync() |> Async.AwaitTask
let data = JsonConvert.DeserializeObject<NameContainer>(reqBody)
let name =
match nameOpt with
| Some n -> n
| None ->
match data with
| null -> ""
| nc -> nc.Name
let responseMessage =
if (String.IsNullOrWhiteSpace(name)) then
"This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
else
"Hello, " + name + ". This HTTP triggered function executed successfully."
return OkObjectResult(responseMessage) :> IActionResult
} |> Async.StartAsTask
工作正常,成功日志:
这是我创建 运行 F# 函数的步骤:
1.Runcmd中的这两条命令:
dotnet new --install Microsoft.Azure.WebJobs.ItemTemplates
dotnet new --install Microsoft.Azure.WebJobs.ProjectTemplates
2.Create 函数应用:
dotnet new func --language F# --name FunctionsInFSharp
3.Create 触发器:
dotnet new http --language F# --name HttpTrigger
4.Add 触发编译:
<Compile Include="HttpTrigger.fs" />
请将以上代码添加到 .fsproj 文件中的 ItemGroup。
5.Change 模板,将这些从 none 更改为内容:
我给出的只是一个简单的F#函数触发成功的例子,请试一试,看能不能解决。:)
经过一周的测试和更改,我找到了一个不理想的解决方案,但它正在运行。
在函数中我这样定义 logInfo:
let logInfo : Action<string> = new Action<string>(fun (x: string) -> log.LogInformation(x))
在我的 C# 库中,我删除了对 Microsoft.Extensions.Logging
的所有引用,并将其替换为:
private Action<string> _logger;
public PaymentGateway(string apiKey, Action<string> logger) {
_logger = logger;
}
至少,我的组件中有日志。我不喜欢这个解决方案,但这是我可以用 F# 做的。