Reputation: 6276
I have a quite big project with Azure Function v2 written in F#. I create a library in C# where in the constructor I can pass a ILogger log
. If only I add this library in the Azure Function project, every function returns an error.
Microsoft.Azure.WebJobs.Host: Cannot bind parameter 'log' to type ILogger. Make sure the parameter Type is supported by the binding
In F# I tried to add
[<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)
...
I saw some posts for example on GitHub or another post where other people have the same issue. Apparently, the solution is to update the Azure Function from v2 to v3 but I can't do that in my case right now.
Is there any solution?
The .fsproj
is
<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>
Upvotes: 0
Views: 362
Reputation: 6276
After a solid week of tests and changes, I found a non-ideal solution but it is working.
In the function I define logInfo like that:
let logInfo : Action<string> = new Action<string>(fun (x: string) -> log.LogInformation(x))
In my C# library, I removed any reference to Microsoft.Extensions.Logging
and I replace it with:
private Action<string> _logger;
public PaymentGateway(string apiKey, Action<string> logger) {
_logger = logger;
}
At least, I have logs in my component. I don't like this solution but it is what I can do with F#.
Upvotes: 0
Reputation: 14113
No matter what, your fs is indeed problematic. I posted here the file and code of function that can be triggered successfully:
This is the structure of my function app:
This is my .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>
And this is my trigger file 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
Works fine, successful log:
These is my step to create and run F# function:
1.Run these two command in cmd:
dotnet new --install Microsoft.Azure.WebJobs.ItemTemplates
dotnet new --install Microsoft.Azure.WebJobs.ProjectTemplates
2.Create function app:
dotnet new func --language F# --name FunctionsInFSharp
3.Create trigger:
dotnet new http --language F# --name HttpTrigger
4.Add trigger to compile:
<Compile Include="HttpTrigger.fs" />
Please add above code to ItemGroup in .fsproj file.
5.Change the template, change these from none to Content:
All I have given is a simple example of how the F# function can be triggered successfully, please try it and let me know whether you can solve it.:)
Upvotes: 1