简体   繁体   English

如何在F#中声明可以通过WebJob的JobHost.CallAsync调用的函数?

[英]How can I declare a function in F# that can be invoked via WebJob's JobHost.CallAsync?

In a C# WebJob , I'm able to manually invoke a public static class method like this: 在C# WebJob中 ,我可以像这样手动调用公共静态类方法:

using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;

namespace foo
{
    public class Program
    {

        [NoAutomaticTrigger]
        public static void Go(TraceWriter log) { ... }

        static void Main()
        {
           var host = new JobHost();
           var methodInfo = typeof(Program).GetMethod("Go");
           host.Call(methodInfo);
           host.RunAndBlock();
        }

methodInfo is a System.Reflection.MethodInfo , and in the debugger I can see that it has Attributes Public | Static | HideBySig methodInfoSystem.Reflection.MethodInfo ,在调试器中,我可以看到它具有“属性” Public | Static | HideBySig Public | Static | HideBySig Public | Static | HideBySig and CustomAttributes Microsoft.Azure.WebJobs.NoAutomaticTriggerAttribute . Public | Static | HideBySig和CustomAttributes Microsoft.Azure.WebJobs.NoAutomaticTriggerAttribute

I'm trying to do this in F#. 我正在尝试在F#中执行此操作。 Here's what I have so far: 这是我到目前为止的内容:

type Foo() =

    [<NoAutomaticTrigger>]
    static member Go (log:TraceWriter) =
        log.Info "hello!"

[<EntryPoint>]
let main argv =
        let theType = typedefof<Foo>
        let methodInfo = theType.GetMethods() |> Seq.find(fun t -> t.Name = "Go")
        host.Call(methodInfo)
        host.RunAndBlock()

The WebJobs runtime doesn't like it: WebJobs运行时不喜欢它:

System.InvalidOperationException
  HResult=0x80131509
  Message='Void Go(Microsoft.Azure.WebJobs.Host.TraceWriter)' can't be invoked from Azure WebJobs SDK. Is it missing Azure WebJobs SDK attributes?
  Source=Microsoft.Azure.WebJobs.Host
  StackTrace:
   at Microsoft.Azure.WebJobs.JobHost.Validate(IFunctionDefinition function, Object key)
   at Microsoft.Azure.WebJobs.JobHost.<CallAsyncCore>d__37.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Azure.WebJobs.JobHost.Call(MethodInfo method)
   at Program.main(String[] argv) in C:\path\to\project\Program.fs:line 110

My F# methodInfo does have the NoAutomaticTrigger attribute. 我的F# methodInfo 确实具有NoAutomaticTrigger属性。 It also has Public and Static, but it's missing HideBySig . 它还具有Public和Static,但是缺少HideBySig Is that likely to matter? 这可能很重要吗? Are there other parts of the MethodInfos that I should be comparing? 我应该比较MethodInfos的其他部分吗?

Here's the relevant source from the webjobs sdk: https://github.com/Azure/azure-webjobs-sdk/blob/v2.2.0/src/Microsoft.Azure.WebJobs.Host/JobHost.cs#L306 以下是来自webjobs sdk的相关资源: https : //github.com/Azure/azure-webjobs-sdk/blob/v2.2.0/src/Microsoft.Azure.WebJobs.Host/JobHost.cs#L306

For what it's worth, I've been able to use TimerTrigger and ServiceBusTrigger from F# successfully; 对于它的价值,我已经能够成功地使用F#中的TimerTrigger和ServiceBusTrigger。 it's just this manual invocation pattern that I'm struggling with. 我正在努力的只是这种手动调用模式。

Next I'm planning to sift through the webjobs source and try to figure out exactly what it's looking for, but I'm hoping there's something obvious someone more experienced with F# and/or webjobs can tell me. 接下来,我打算筛选一下webjobs的源代码,并试图弄清楚它到底在寻找什么,但是我希望有一些对F#和/或webjobs更有经验的人可以告诉我。

Debugging through the WebJobs source, I eventually wound up at the DefaultTypeLocator , which picks up classes that are marked IsPublic . 通过WebJobs源进行调试,最终我找到了DefaultTypeLocator ,它拾取了标记为IsPublic的类。 I experimented with my F# declarations, but couldn't seem to achieve that; 我尝试了F#声明,但似乎无法实现。 I only managed to produce IsNestedPublic . 我只设法产生IsNestedPublic

So I tried another approach: instead of trying to write an F# function discoverable by the existing WebJobs runtime, I overrode the discovery logic: 因此,我尝试了另一种方法:我没有尝试编写现有WebJobs运行时可发现的F#函数,而是覆盖了发现逻辑:

type myTypeLocator() =
    interface ITypeLocator with
        member this.GetTypes () =
            new System.Collections.Generic.List<Type>([ typedefof<Foo> ]) :> IReadOnlyList<Type>

... ...

let config = new JobHostConfiguration (
                    DashboardConnectionString = dashboardConnectionString,
                    StorageConnectionString = storageConnectionString,
                    TypeLocator = new myTypeLocator()
                )

let host = new JobHost(config)

This worked: my functions are discovered and I'm able to JobHost.Call them. 行得通 :我的功能被发现,我能够JobHost.Call他们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM